diff --git a/404.html b/404.html new file mode 100644 index 0000000000..03490d43e7 --- /dev/null +++ b/404.html @@ -0,0 +1,188 @@ + + + + + + + + + + + Page Not Found + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Sorry, but the page you were trying to view does not exist.

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CNAME b/CNAME new file mode 100644 index 0000000000..7d9473e42e --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +wiki.uqbar.org diff --git a/articles.html b/articles.html new file mode 100644 index 0000000000..d8868271ba --- /dev/null +++ b/articles.html @@ -0,0 +1,1165 @@ + + + + + + + + + + + wiki.template landing page + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Articulos de la wiki

+ + + +


+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/app-1e946f931f577cd478e6e6610915be9d.css b/assets/app-1e946f931f577cd478e6e6610915be9d.css new file mode 100644 index 0000000000..6bed1c0eb2 --- /dev/null +++ b/assets/app-1e946f931f577cd478e6e6610915be9d.css @@ -0,0 +1 @@ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.hljs{display:block;overflow-x:auto;padding:0.5em;background:#f0f0f0;-webkit-text-size-adjust:none}.hljs,.hljs-subst,.hljs-tag .hljs-title,.nginx .hljs-title{color:black}.hljs-string,.hljs-title,.hljs-constant,.hljs-parent,.hljs-tag .hljs-value,.hljs-rule .hljs-value,.hljs-preprocessor,.hljs-pragma,.hljs-name,.haml .hljs-symbol,.ruby .hljs-symbol,.ruby .hljs-symbol .hljs-string,.hljs-template_tag,.django .hljs-variable,.smalltalk .hljs-class,.hljs-addition,.hljs-flow,.hljs-stream,.bash .hljs-variable,.pf .hljs-variable,.apache .hljs-tag,.apache .hljs-cbracket,.tex .hljs-command,.tex .hljs-special,.erlang_repl .hljs-function_or_atom,.asciidoc .hljs-header,.markdown .hljs-header,.coffeescript .hljs-attribute,.tp .hljs-variable{color:#800}.smartquote,.hljs-comment,.hljs-annotation,.diff .hljs-header,.hljs-chunk,.asciidoc .hljs-blockquote,.markdown .hljs-blockquote{color:#888}.hljs-number,.hljs-date,.hljs-regexp,.hljs-literal,.hljs-hexcolor,.smalltalk .hljs-symbol,.smalltalk .hljs-char,.go .hljs-constant,.hljs-change,.lasso .hljs-variable,.makefile .hljs-variable,.asciidoc .hljs-bullet,.markdown .hljs-bullet,.asciidoc .hljs-link_url,.markdown .hljs-link_url{color:#080}.hljs-label,.ruby .hljs-string,.hljs-decorator,.hljs-filter .hljs-argument,.hljs-localvars,.hljs-array,.hljs-attr_selector,.hljs-important,.hljs-pseudo,.hljs-pi,.haml .hljs-bullet,.hljs-doctype,.hljs-deletion,.hljs-envvar,.hljs-shebang,.apache .hljs-sqbracket,.nginx .hljs-built_in,.tex .hljs-formula,.erlang_repl .hljs-reserved,.hljs-prompt,.asciidoc .hljs-link_label,.markdown .hljs-link_label,.vhdl .hljs-attribute,.clojure .hljs-attribute,.asciidoc .hljs-attribute,.lasso .hljs-attribute,.coffeescript .hljs-property,.hljs-phony{color:#88f}.hljs-keyword,.hljs-id,.hljs-title,.hljs-built_in,.css .hljs-tag,.hljs-doctag,.smalltalk .hljs-class,.hljs-winutils,.bash .hljs-variable,.pf .hljs-variable,.apache .hljs-tag,.hljs-type,.hljs-typename,.tex .hljs-command,.asciidoc .hljs-strong,.markdown .hljs-strong,.hljs-request,.hljs-status,.tp .hljs-data,.tp .hljs-io{font-weight:bold}.asciidoc .hljs-emphasis,.markdown .hljs-emphasis,.tp .hljs-units{font-style:italic}.nginx .hljs-built_in{font-weight:normal}.coffeescript .javascript,.javascript .xml,.lasso .markup,.tex .hljs-formula,.xml .javascript,.xml .vbscript,.xml .css,.xml .hljs-cdata{opacity:0.5}meta.foundation-version{font-family:"/5.5.2/"}meta.foundation-mq-small{font-family:"/only screen/";width:0}meta.foundation-mq-small-only{font-family:"/only screen and (max-width: 40em)/";width:0}meta.foundation-mq-medium{font-family:"/only screen and (min-width:40.0625em)/";width:40.0625em}meta.foundation-mq-medium-only{font-family:"/only screen and (min-width:40.0625em) and (max-width:64em)/";width:40.0625em}meta.foundation-mq-large{font-family:"/only screen and (min-width:64.0625em)/";width:64.0625em}meta.foundation-mq-large-only{font-family:"/only screen and (min-width:64.0625em) and (max-width:90em)/";width:64.0625em}meta.foundation-mq-xlarge{font-family:"/only screen and (min-width:90.0625em)/";width:90.0625em}meta.foundation-mq-xlarge-only{font-family:"/only screen and (min-width:90.0625em) and (max-width:120em)/";width:90.0625em}meta.foundation-mq-xxlarge{font-family:"/only screen and (min-width:120.0625em)/";width:120.0625em}meta.foundation-data-attribute-namespace{font-family:false}html,body{height:100%}html{box-sizing:border-box}*,*:before,*:after{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}html,body{font-size:100%}body{background:#FFFFFF;color:#222222;cursor:auto;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-style:normal;font-weight:normal;line-height:150%;margin:0;padding:0;position:relative}a:hover{cursor:pointer}img{max-width:100%;height:auto}img{-ms-interpolation-mode:bicubic}#map_canvas img,#map_canvas embed,#map_canvas object,.map_canvas img,.map_canvas embed,.map_canvas object,.mqa-display img,.mqa-display embed,.mqa-display object{max-width:none !important}.left{float:left !important}.right{float:right !important}.clearfix:before,.clearfix:after{content:" ";display:table}.clearfix:after{clear:both}.hide{display:none}.invisible{visibility:hidden}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}img{display:inline-block;vertical-align:middle}textarea{height:auto;min-height:50px}select{width:100%}.row{margin:0 auto;max-width:62.5rem;width:100%}.row:before,.row:after{content:" ";display:table}.row:after{clear:both}.row.collapse>.column,.row.collapse>.columns{padding-left:0;padding-right:0}.row.collapse .row{margin-left:0;margin-right:0}.row .row{margin:0 -0.9375rem;max-width:none;width:auto}.row .row:before,.row .row:after{content:" ";display:table}.row .row:after{clear:both}.row .row.collapse{margin:0;max-width:none;width:auto}.row .row.collapse:before,.row .row.collapse:after{content:" ";display:table}.row .row.collapse:after{clear:both}.column,.columns{padding-left:0.9375rem;padding-right:0.9375rem;width:100%;float:left}.column+.column:last-child,.columns+.column:last-child,.column+.columns:last-child,.columns+.columns:last-child{float:right}.column+.column.end,.columns+.column.end,.column+.columns.end,.columns+.columns.end{float:left}@media only screen{.small-push-0{position:relative;left:0;right:auto}.small-pull-0{position:relative;right:0;left:auto}.small-push-1{position:relative;left:8.3333333333%;right:auto}.small-pull-1{position:relative;right:8.3333333333%;left:auto}.small-push-2{position:relative;left:16.6666666667%;right:auto}.small-pull-2{position:relative;right:16.6666666667%;left:auto}.small-push-3{position:relative;left:25%;right:auto}.small-pull-3{position:relative;right:25%;left:auto}.small-push-4{position:relative;left:33.3333333333%;right:auto}.small-pull-4{position:relative;right:33.3333333333%;left:auto}.small-push-5{position:relative;left:41.6666666667%;right:auto}.small-pull-5{position:relative;right:41.6666666667%;left:auto}.small-push-6{position:relative;left:50%;right:auto}.small-pull-6{position:relative;right:50%;left:auto}.small-push-7{position:relative;left:58.3333333333%;right:auto}.small-pull-7{position:relative;right:58.3333333333%;left:auto}.small-push-8{position:relative;left:66.6666666667%;right:auto}.small-pull-8{position:relative;right:66.6666666667%;left:auto}.small-push-9{position:relative;left:75%;right:auto}.small-pull-9{position:relative;right:75%;left:auto}.small-push-10{position:relative;left:83.3333333333%;right:auto}.small-pull-10{position:relative;right:83.3333333333%;left:auto}.small-push-11{position:relative;left:91.6666666667%;right:auto}.small-pull-11{position:relative;right:91.6666666667%;left:auto}.column,.columns{position:relative;padding-left:0.9375rem;padding-right:0.9375rem;float:left}.small-1{width:8.3333333333%}.small-2{width:16.6666666667%}.small-3{width:25%}.small-4{width:33.3333333333%}.small-5{width:41.6666666667%}.small-6{width:50%}.small-7{width:58.3333333333%}.small-8{width:66.6666666667%}.small-9{width:75%}.small-10{width:83.3333333333%}.small-11{width:91.6666666667%}.small-12{width:100%}.small-offset-0{margin-left:0 !important}.small-offset-1{margin-left:8.3333333333% !important}.small-offset-2{margin-left:16.6666666667% !important}.small-offset-3{margin-left:25% !important}.small-offset-4{margin-left:33.3333333333% !important}.small-offset-5{margin-left:41.6666666667% !important}.small-offset-6{margin-left:50% !important}.small-offset-7{margin-left:58.3333333333% !important}.small-offset-8{margin-left:66.6666666667% !important}.small-offset-9{margin-left:75% !important}.small-offset-10{margin-left:83.3333333333% !important}.small-offset-11{margin-left:91.6666666667% !important}.small-reset-order{float:left;left:auto;margin-left:0;margin-right:0;right:auto}.column.small-centered,.columns.small-centered{margin-left:auto;margin-right:auto;float:none}.column.small-uncentered,.columns.small-uncentered{float:left;margin-left:0;margin-right:0}.column.small-centered:last-child,.columns.small-centered:last-child{float:none}.column.small-uncentered:last-child,.columns.small-uncentered:last-child{float:left}.column.small-uncentered.opposite,.columns.small-uncentered.opposite{float:right}.row.small-collapse>.column,.row.small-collapse>.columns{padding-left:0;padding-right:0}.row.small-collapse .row{margin-left:0;margin-right:0}.row.small-uncollapse>.column,.row.small-uncollapse>.columns{padding-left:0.9375rem;padding-right:0.9375rem;float:left}}@media only screen and (min-width: 40.0625em){.medium-push-0{position:relative;left:0;right:auto}.medium-pull-0{position:relative;right:0;left:auto}.medium-push-1{position:relative;left:8.3333333333%;right:auto}.medium-pull-1{position:relative;right:8.3333333333%;left:auto}.medium-push-2{position:relative;left:16.6666666667%;right:auto}.medium-pull-2{position:relative;right:16.6666666667%;left:auto}.medium-push-3{position:relative;left:25%;right:auto}.medium-pull-3{position:relative;right:25%;left:auto}.medium-push-4{position:relative;left:33.3333333333%;right:auto}.medium-pull-4{position:relative;right:33.3333333333%;left:auto}.medium-push-5{position:relative;left:41.6666666667%;right:auto}.medium-pull-5{position:relative;right:41.6666666667%;left:auto}.medium-push-6{position:relative;left:50%;right:auto}.medium-pull-6{position:relative;right:50%;left:auto}.medium-push-7{position:relative;left:58.3333333333%;right:auto}.medium-pull-7{position:relative;right:58.3333333333%;left:auto}.medium-push-8{position:relative;left:66.6666666667%;right:auto}.medium-pull-8{position:relative;right:66.6666666667%;left:auto}.medium-push-9{position:relative;left:75%;right:auto}.medium-pull-9{position:relative;right:75%;left:auto}.medium-push-10{position:relative;left:83.3333333333%;right:auto}.medium-pull-10{position:relative;right:83.3333333333%;left:auto}.medium-push-11{position:relative;left:91.6666666667%;right:auto}.medium-pull-11{position:relative;right:91.6666666667%;left:auto}.column,.columns{position:relative;padding-left:0.9375rem;padding-right:0.9375rem;float:left}.medium-1{width:8.3333333333%}.medium-2{width:16.6666666667%}.medium-3{width:25%}.medium-4{width:33.3333333333%}.medium-5{width:41.6666666667%}.medium-6{width:50%}.medium-7{width:58.3333333333%}.medium-8{width:66.6666666667%}.medium-9{width:75%}.medium-10{width:83.3333333333%}.medium-11{width:91.6666666667%}.medium-12{width:100%}.medium-offset-0{margin-left:0 !important}.medium-offset-1{margin-left:8.3333333333% !important}.medium-offset-2{margin-left:16.6666666667% !important}.medium-offset-3{margin-left:25% !important}.medium-offset-4{margin-left:33.3333333333% !important}.medium-offset-5{margin-left:41.6666666667% !important}.medium-offset-6{margin-left:50% !important}.medium-offset-7{margin-left:58.3333333333% !important}.medium-offset-8{margin-left:66.6666666667% !important}.medium-offset-9{margin-left:75% !important}.medium-offset-10{margin-left:83.3333333333% !important}.medium-offset-11{margin-left:91.6666666667% !important}.medium-reset-order{float:left;left:auto;margin-left:0;margin-right:0;right:auto}.column.medium-centered,.columns.medium-centered{margin-left:auto;margin-right:auto;float:none}.column.medium-uncentered,.columns.medium-uncentered{float:left;margin-left:0;margin-right:0}.column.medium-centered:last-child,.columns.medium-centered:last-child{float:none}.column.medium-uncentered:last-child,.columns.medium-uncentered:last-child{float:left}.column.medium-uncentered.opposite,.columns.medium-uncentered.opposite{float:right}.row.medium-collapse>.column,.row.medium-collapse>.columns{padding-left:0;padding-right:0}.row.medium-collapse .row{margin-left:0;margin-right:0}.row.medium-uncollapse>.column,.row.medium-uncollapse>.columns{padding-left:0.9375rem;padding-right:0.9375rem;float:left}.push-0{position:relative;left:0;right:auto}.pull-0{position:relative;right:0;left:auto}.push-1{position:relative;left:8.3333333333%;right:auto}.pull-1{position:relative;right:8.3333333333%;left:auto}.push-2{position:relative;left:16.6666666667%;right:auto}.pull-2{position:relative;right:16.6666666667%;left:auto}.push-3{position:relative;left:25%;right:auto}.pull-3{position:relative;right:25%;left:auto}.push-4{position:relative;left:33.3333333333%;right:auto}.pull-4{position:relative;right:33.3333333333%;left:auto}.push-5{position:relative;left:41.6666666667%;right:auto}.pull-5{position:relative;right:41.6666666667%;left:auto}.push-6{position:relative;left:50%;right:auto}.pull-6{position:relative;right:50%;left:auto}.push-7{position:relative;left:58.3333333333%;right:auto}.pull-7{position:relative;right:58.3333333333%;left:auto}.push-8{position:relative;left:66.6666666667%;right:auto}.pull-8{position:relative;right:66.6666666667%;left:auto}.push-9{position:relative;left:75%;right:auto}.pull-9{position:relative;right:75%;left:auto}.push-10{position:relative;left:83.3333333333%;right:auto}.pull-10{position:relative;right:83.3333333333%;left:auto}.push-11{position:relative;left:91.6666666667%;right:auto}.pull-11{position:relative;right:91.6666666667%;left:auto}}@media only screen and (min-width: 64.0625em){.large-push-0{position:relative;left:0;right:auto}.large-pull-0{position:relative;right:0;left:auto}.large-push-1{position:relative;left:8.3333333333%;right:auto}.large-pull-1{position:relative;right:8.3333333333%;left:auto}.large-push-2{position:relative;left:16.6666666667%;right:auto}.large-pull-2{position:relative;right:16.6666666667%;left:auto}.large-push-3{position:relative;left:25%;right:auto}.large-pull-3{position:relative;right:25%;left:auto}.large-push-4{position:relative;left:33.3333333333%;right:auto}.large-pull-4{position:relative;right:33.3333333333%;left:auto}.large-push-5{position:relative;left:41.6666666667%;right:auto}.large-pull-5{position:relative;right:41.6666666667%;left:auto}.large-push-6{position:relative;left:50%;right:auto}.large-pull-6{position:relative;right:50%;left:auto}.large-push-7{position:relative;left:58.3333333333%;right:auto}.large-pull-7{position:relative;right:58.3333333333%;left:auto}.large-push-8{position:relative;left:66.6666666667%;right:auto}.large-pull-8{position:relative;right:66.6666666667%;left:auto}.large-push-9{position:relative;left:75%;right:auto}.large-pull-9{position:relative;right:75%;left:auto}.large-push-10{position:relative;left:83.3333333333%;right:auto}.large-pull-10{position:relative;right:83.3333333333%;left:auto}.large-push-11{position:relative;left:91.6666666667%;right:auto}.large-pull-11{position:relative;right:91.6666666667%;left:auto}.column,.columns{position:relative;padding-left:0.9375rem;padding-right:0.9375rem;float:left}.large-1{width:8.3333333333%}.large-2{width:16.6666666667%}.large-3{width:25%}.large-4{width:33.3333333333%}.large-5{width:41.6666666667%}.large-6{width:50%}.large-7{width:58.3333333333%}.large-8{width:66.6666666667%}.large-9{width:75%}.large-10{width:83.3333333333%}.large-11{width:91.6666666667%}.large-12{width:100%}.large-offset-0{margin-left:0 !important}.large-offset-1{margin-left:8.3333333333% !important}.large-offset-2{margin-left:16.6666666667% !important}.large-offset-3{margin-left:25% !important}.large-offset-4{margin-left:33.3333333333% !important}.large-offset-5{margin-left:41.6666666667% !important}.large-offset-6{margin-left:50% !important}.large-offset-7{margin-left:58.3333333333% !important}.large-offset-8{margin-left:66.6666666667% !important}.large-offset-9{margin-left:75% !important}.large-offset-10{margin-left:83.3333333333% !important}.large-offset-11{margin-left:91.6666666667% !important}.large-reset-order{float:left;left:auto;margin-left:0;margin-right:0;right:auto}.column.large-centered,.columns.large-centered{margin-left:auto;margin-right:auto;float:none}.column.large-uncentered,.columns.large-uncentered{float:left;margin-left:0;margin-right:0}.column.large-centered:last-child,.columns.large-centered:last-child{float:none}.column.large-uncentered:last-child,.columns.large-uncentered:last-child{float:left}.column.large-uncentered.opposite,.columns.large-uncentered.opposite{float:right}.row.large-collapse>.column,.row.large-collapse>.columns{padding-left:0;padding-right:0}.row.large-collapse .row{margin-left:0;margin-right:0}.row.large-uncollapse>.column,.row.large-uncollapse>.columns{padding-left:0.9375rem;padding-right:0.9375rem;float:left}.push-0{position:relative;left:0;right:auto}.pull-0{position:relative;right:0;left:auto}.push-1{position:relative;left:8.3333333333%;right:auto}.pull-1{position:relative;right:8.3333333333%;left:auto}.push-2{position:relative;left:16.6666666667%;right:auto}.pull-2{position:relative;right:16.6666666667%;left:auto}.push-3{position:relative;left:25%;right:auto}.pull-3{position:relative;right:25%;left:auto}.push-4{position:relative;left:33.3333333333%;right:auto}.pull-4{position:relative;right:33.3333333333%;left:auto}.push-5{position:relative;left:41.6666666667%;right:auto}.pull-5{position:relative;right:41.6666666667%;left:auto}.push-6{position:relative;left:50%;right:auto}.pull-6{position:relative;right:50%;left:auto}.push-7{position:relative;left:58.3333333333%;right:auto}.pull-7{position:relative;right:58.3333333333%;left:auto}.push-8{position:relative;left:66.6666666667%;right:auto}.pull-8{position:relative;right:66.6666666667%;left:auto}.push-9{position:relative;left:75%;right:auto}.pull-9{position:relative;right:75%;left:auto}.push-10{position:relative;left:83.3333333333%;right:auto}.pull-10{position:relative;right:83.3333333333%;left:auto}.push-11{position:relative;left:91.6666666667%;right:auto}.pull-11{position:relative;right:91.6666666667%;left:auto}}.accordion{margin-bottom:0}.accordion:before,.accordion:after{content:" ";display:table}.accordion:after{clear:both}.accordion .accordion-navigation,.accordion dd{display:block;margin-bottom:0 !important}.accordion .accordion-navigation.active>a,.accordion dd.active>a{background:#e8e8e8}.accordion .accordion-navigation>a,.accordion dd>a{background:#EFEFEF;color:#222222;display:block;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size:1rem;padding:1rem}.accordion .accordion-navigation>a:hover,.accordion dd>a:hover{background:#e3e3e3}.accordion .accordion-navigation>.content,.accordion dd>.content{display:none;padding:0.9375rem}.accordion .accordion-navigation>.content.active,.accordion dd>.content.active{background:#FFFFFF;display:block}.alert-box{border-style:solid;border-width:1px;display:block;font-size:0.8125rem;font-weight:normal;margin-bottom:1.25rem;padding:0.875rem 1.5rem 0.875rem 0.875rem;position:relative;transition:opacity 300ms ease-out;background-color:#008CBA;border-color:#0078a0;color:#FFFFFF}.alert-box .close{right:0.25rem;background:inherit;color:#333333;font-size:1.375rem;line-height:.9;margin-top:-0.6875rem;opacity:0.3;padding:0 6px 4px;position:absolute;top:50%}.alert-box .close:hover,.alert-box .close:focus{opacity:0.5}.alert-box.radius{border-radius:3px}.alert-box.round{border-radius:1000px}.alert-box.success{background-color:#43AC6A;border-color:#3a945b;color:#FFFFFF}.alert-box.alert{background-color:#f04124;border-color:#de2d0f;color:#FFFFFF}.alert-box.secondary{background-color:#e7e7e7;border-color:#c7c7c7;color:#4f4f4f}.alert-box.warning{background-color:#f08a24;border-color:#de770f;color:#FFFFFF}.alert-box.info{background-color:#a0d3e8;border-color:#74bfdd;color:#4f4f4f}.alert-box.alert-close{opacity:0}[class*="block-grid-"]{display:block;padding:0;margin:0 -0.625rem}[class*="block-grid-"]:before,[class*="block-grid-"]:after{content:" ";display:table}[class*="block-grid-"]:after{clear:both}[class*="block-grid-"]>li{display:block;float:left;height:auto;padding:0 0.625rem 1.25rem}@media only screen{.small-block-grid-1>li{list-style:none;width:100%}.small-block-grid-1>li:nth-of-type(1n){clear:none}.small-block-grid-1>li:nth-of-type(1n+1){clear:both}.small-block-grid-2>li{list-style:none;width:50%}.small-block-grid-2>li:nth-of-type(1n){clear:none}.small-block-grid-2>li:nth-of-type(2n+1){clear:both}.small-block-grid-3>li{list-style:none;width:33.3333333333%}.small-block-grid-3>li:nth-of-type(1n){clear:none}.small-block-grid-3>li:nth-of-type(3n+1){clear:both}.small-block-grid-4>li{list-style:none;width:25%}.small-block-grid-4>li:nth-of-type(1n){clear:none}.small-block-grid-4>li:nth-of-type(4n+1){clear:both}.small-block-grid-5>li{list-style:none;width:20%}.small-block-grid-5>li:nth-of-type(1n){clear:none}.small-block-grid-5>li:nth-of-type(5n+1){clear:both}.small-block-grid-6>li{list-style:none;width:16.6666666667%}.small-block-grid-6>li:nth-of-type(1n){clear:none}.small-block-grid-6>li:nth-of-type(6n+1){clear:both}.small-block-grid-7>li{list-style:none;width:14.2857142857%}.small-block-grid-7>li:nth-of-type(1n){clear:none}.small-block-grid-7>li:nth-of-type(7n+1){clear:both}.small-block-grid-8>li{list-style:none;width:12.5%}.small-block-grid-8>li:nth-of-type(1n){clear:none}.small-block-grid-8>li:nth-of-type(8n+1){clear:both}.small-block-grid-9>li{list-style:none;width:11.1111111111%}.small-block-grid-9>li:nth-of-type(1n){clear:none}.small-block-grid-9>li:nth-of-type(9n+1){clear:both}.small-block-grid-10>li{list-style:none;width:10%}.small-block-grid-10>li:nth-of-type(1n){clear:none}.small-block-grid-10>li:nth-of-type(10n+1){clear:both}.small-block-grid-11>li{list-style:none;width:9.0909090909%}.small-block-grid-11>li:nth-of-type(1n){clear:none}.small-block-grid-11>li:nth-of-type(11n+1){clear:both}.small-block-grid-12>li{list-style:none;width:8.3333333333%}.small-block-grid-12>li:nth-of-type(1n){clear:none}.small-block-grid-12>li:nth-of-type(12n+1){clear:both}}@media only screen and (min-width: 40.0625em){.medium-block-grid-1>li{list-style:none;width:100%}.medium-block-grid-1>li:nth-of-type(1n){clear:none}.medium-block-grid-1>li:nth-of-type(1n+1){clear:both}.medium-block-grid-2>li{list-style:none;width:50%}.medium-block-grid-2>li:nth-of-type(1n){clear:none}.medium-block-grid-2>li:nth-of-type(2n+1){clear:both}.medium-block-grid-3>li{list-style:none;width:33.3333333333%}.medium-block-grid-3>li:nth-of-type(1n){clear:none}.medium-block-grid-3>li:nth-of-type(3n+1){clear:both}.medium-block-grid-4>li{list-style:none;width:25%}.medium-block-grid-4>li:nth-of-type(1n){clear:none}.medium-block-grid-4>li:nth-of-type(4n+1){clear:both}.medium-block-grid-5>li{list-style:none;width:20%}.medium-block-grid-5>li:nth-of-type(1n){clear:none}.medium-block-grid-5>li:nth-of-type(5n+1){clear:both}.medium-block-grid-6>li{list-style:none;width:16.6666666667%}.medium-block-grid-6>li:nth-of-type(1n){clear:none}.medium-block-grid-6>li:nth-of-type(6n+1){clear:both}.medium-block-grid-7>li{list-style:none;width:14.2857142857%}.medium-block-grid-7>li:nth-of-type(1n){clear:none}.medium-block-grid-7>li:nth-of-type(7n+1){clear:both}.medium-block-grid-8>li{list-style:none;width:12.5%}.medium-block-grid-8>li:nth-of-type(1n){clear:none}.medium-block-grid-8>li:nth-of-type(8n+1){clear:both}.medium-block-grid-9>li{list-style:none;width:11.1111111111%}.medium-block-grid-9>li:nth-of-type(1n){clear:none}.medium-block-grid-9>li:nth-of-type(9n+1){clear:both}.medium-block-grid-10>li{list-style:none;width:10%}.medium-block-grid-10>li:nth-of-type(1n){clear:none}.medium-block-grid-10>li:nth-of-type(10n+1){clear:both}.medium-block-grid-11>li{list-style:none;width:9.0909090909%}.medium-block-grid-11>li:nth-of-type(1n){clear:none}.medium-block-grid-11>li:nth-of-type(11n+1){clear:both}.medium-block-grid-12>li{list-style:none;width:8.3333333333%}.medium-block-grid-12>li:nth-of-type(1n){clear:none}.medium-block-grid-12>li:nth-of-type(12n+1){clear:both}}@media only screen and (min-width: 64.0625em){.large-block-grid-1>li{list-style:none;width:100%}.large-block-grid-1>li:nth-of-type(1n){clear:none}.large-block-grid-1>li:nth-of-type(1n+1){clear:both}.large-block-grid-2>li{list-style:none;width:50%}.large-block-grid-2>li:nth-of-type(1n){clear:none}.large-block-grid-2>li:nth-of-type(2n+1){clear:both}.large-block-grid-3>li{list-style:none;width:33.3333333333%}.large-block-grid-3>li:nth-of-type(1n){clear:none}.large-block-grid-3>li:nth-of-type(3n+1){clear:both}.large-block-grid-4>li{list-style:none;width:25%}.large-block-grid-4>li:nth-of-type(1n){clear:none}.large-block-grid-4>li:nth-of-type(4n+1){clear:both}.large-block-grid-5>li{list-style:none;width:20%}.large-block-grid-5>li:nth-of-type(1n){clear:none}.large-block-grid-5>li:nth-of-type(5n+1){clear:both}.large-block-grid-6>li{list-style:none;width:16.6666666667%}.large-block-grid-6>li:nth-of-type(1n){clear:none}.large-block-grid-6>li:nth-of-type(6n+1){clear:both}.large-block-grid-7>li{list-style:none;width:14.2857142857%}.large-block-grid-7>li:nth-of-type(1n){clear:none}.large-block-grid-7>li:nth-of-type(7n+1){clear:both}.large-block-grid-8>li{list-style:none;width:12.5%}.large-block-grid-8>li:nth-of-type(1n){clear:none}.large-block-grid-8>li:nth-of-type(8n+1){clear:both}.large-block-grid-9>li{list-style:none;width:11.1111111111%}.large-block-grid-9>li:nth-of-type(1n){clear:none}.large-block-grid-9>li:nth-of-type(9n+1){clear:both}.large-block-grid-10>li{list-style:none;width:10%}.large-block-grid-10>li:nth-of-type(1n){clear:none}.large-block-grid-10>li:nth-of-type(10n+1){clear:both}.large-block-grid-11>li{list-style:none;width:9.0909090909%}.large-block-grid-11>li:nth-of-type(1n){clear:none}.large-block-grid-11>li:nth-of-type(11n+1){clear:both}.large-block-grid-12>li{list-style:none;width:8.3333333333%}.large-block-grid-12>li:nth-of-type(1n){clear:none}.large-block-grid-12>li:nth-of-type(12n+1){clear:both}}.breadcrumbs{border-style:solid;border-width:1px;display:block;list-style:none;margin-left:0;overflow:hidden;padding:0.5625rem 0.875rem 0.5625rem;background-color:#f4f4f4;border-color:gainsboro;border-radius:3px}.breadcrumbs>*{color:#008CBA;float:left;font-size:0.6875rem;line-height:0.6875rem;margin:0;text-transform:uppercase}.breadcrumbs>*:hover a,.breadcrumbs>*:focus a{text-decoration:underline}.breadcrumbs>* a{color:#008CBA}.breadcrumbs>*.current{color:#333333;cursor:default}.breadcrumbs>*.current a{color:#333333;cursor:default}.breadcrumbs>*.current:hover,.breadcrumbs>*.current:hover a,.breadcrumbs>*.current:focus,.breadcrumbs>*.current:focus a{text-decoration:none}.breadcrumbs>*.unavailable{color:#999999}.breadcrumbs>*.unavailable a{color:#999999}.breadcrumbs>*.unavailable:hover,.breadcrumbs>*.unavailable:hover a,.breadcrumbs>*.unavailable:focus,.breadcrumbs>*.unavailable a:focus{color:#999999;cursor:not-allowed;text-decoration:none}.breadcrumbs>*:before{color:#AAAAAA;content:"/";margin:0 0.75rem;position:relative;top:1px}.breadcrumbs>*:first-child:before{content:" ";margin:0}[aria-label="breadcrumbs"] [aria-hidden="true"]:after{content:"/"}button,.button{-webkit-appearance:none;-moz-appearance:none;border-radius:0;border-style:solid;border-width:0;cursor:pointer;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-weight:normal;line-height:normal;margin:0 0 0.5rem;position:relative;text-align:center;text-decoration:none;display:inline-block;padding:1rem 2rem 1.0625rem 2rem;font-size:1rem;background-color:#008CBA;border-color:#007095;color:#FFFFFF;transition:background-color 300ms ease-out}button:hover,button:focus,.button:hover,.button:focus{background-color:#007095}button:hover,button:focus,.button:hover,.button:focus{color:#FFFFFF}button.secondary,.button.secondary{background-color:#e7e7e7;border-color:#b9b9b9;color:#333333}button.secondary:hover,button.secondary:focus,.button.secondary:hover,.button.secondary:focus{background-color:#b9b9b9}button.secondary:hover,button.secondary:focus,.button.secondary:hover,.button.secondary:focus{color:#333333}button.success,.button.success{background-color:#43AC6A;border-color:#368a55;color:#FFFFFF}button.success:hover,button.success:focus,.button.success:hover,.button.success:focus{background-color:#368a55}button.success:hover,button.success:focus,.button.success:hover,.button.success:focus{color:#FFFFFF}button.alert,.button.alert{background-color:#f04124;border-color:#cf2a0e;color:#FFFFFF}button.alert:hover,button.alert:focus,.button.alert:hover,.button.alert:focus{background-color:#cf2a0e}button.alert:hover,button.alert:focus,.button.alert:hover,.button.alert:focus{color:#FFFFFF}button.warning,.button.warning{background-color:#f08a24;border-color:#cf6e0e;color:#FFFFFF}button.warning:hover,button.warning:focus,.button.warning:hover,.button.warning:focus{background-color:#cf6e0e}button.warning:hover,button.warning:focus,.button.warning:hover,.button.warning:focus{color:#FFFFFF}button.info,.button.info{background-color:#a0d3e8;border-color:#61b6d9;color:#333333}button.info:hover,button.info:focus,.button.info:hover,.button.info:focus{background-color:#61b6d9}button.info:hover,button.info:focus,.button.info:hover,.button.info:focus{color:#FFFFFF}button.large,.button.large{padding:1.125rem 2.25rem 1.1875rem 2.25rem;font-size:1.25rem}button.small,.button.small{padding:0.875rem 1.75rem 0.9375rem 1.75rem;font-size:0.8125rem}button.tiny,.button.tiny{padding:0.625rem 1.25rem 0.6875rem 1.25rem;font-size:0.6875rem}button.expand,.button.expand{padding-left:0;padding-right:0;width:100%}button.left-align,.button.left-align{text-align:left;text-indent:0.75rem}button.right-align,.button.right-align{text-align:right;padding-right:0.75rem}button.radius,.button.radius{border-radius:3px}button.round,.button.round{border-radius:1000px}button.disabled,button[disabled],.button.disabled,.button[disabled]{background-color:#008CBA;border-color:#007095;color:#FFFFFF;box-shadow:none;cursor:default;opacity:0.7}button.disabled:hover,button.disabled:focus,button[disabled]:hover,button[disabled]:focus,.button.disabled:hover,.button.disabled:focus,.button[disabled]:hover,.button[disabled]:focus{background-color:#007095}button.disabled:hover,button.disabled:focus,button[disabled]:hover,button[disabled]:focus,.button.disabled:hover,.button.disabled:focus,.button[disabled]:hover,.button[disabled]:focus{color:#FFFFFF}button.disabled:hover,button.disabled:focus,button[disabled]:hover,button[disabled]:focus,.button.disabled:hover,.button.disabled:focus,.button[disabled]:hover,.button[disabled]:focus{background-color:#008CBA}button.disabled.secondary,button[disabled].secondary,.button.disabled.secondary,.button[disabled].secondary{background-color:#e7e7e7;border-color:#b9b9b9;color:#333333;box-shadow:none;cursor:default;opacity:0.7}button.disabled.secondary:hover,button.disabled.secondary:focus,button[disabled].secondary:hover,button[disabled].secondary:focus,.button.disabled.secondary:hover,.button.disabled.secondary:focus,.button[disabled].secondary:hover,.button[disabled].secondary:focus{background-color:#b9b9b9}button.disabled.secondary:hover,button.disabled.secondary:focus,button[disabled].secondary:hover,button[disabled].secondary:focus,.button.disabled.secondary:hover,.button.disabled.secondary:focus,.button[disabled].secondary:hover,.button[disabled].secondary:focus{color:#333333}button.disabled.secondary:hover,button.disabled.secondary:focus,button[disabled].secondary:hover,button[disabled].secondary:focus,.button.disabled.secondary:hover,.button.disabled.secondary:focus,.button[disabled].secondary:hover,.button[disabled].secondary:focus{background-color:#e7e7e7}button.disabled.success,button[disabled].success,.button.disabled.success,.button[disabled].success{background-color:#43AC6A;border-color:#368a55;color:#FFFFFF;box-shadow:none;cursor:default;opacity:0.7}button.disabled.success:hover,button.disabled.success:focus,button[disabled].success:hover,button[disabled].success:focus,.button.disabled.success:hover,.button.disabled.success:focus,.button[disabled].success:hover,.button[disabled].success:focus{background-color:#368a55}button.disabled.success:hover,button.disabled.success:focus,button[disabled].success:hover,button[disabled].success:focus,.button.disabled.success:hover,.button.disabled.success:focus,.button[disabled].success:hover,.button[disabled].success:focus{color:#FFFFFF}button.disabled.success:hover,button.disabled.success:focus,button[disabled].success:hover,button[disabled].success:focus,.button.disabled.success:hover,.button.disabled.success:focus,.button[disabled].success:hover,.button[disabled].success:focus{background-color:#43AC6A}button.disabled.alert,button[disabled].alert,.button.disabled.alert,.button[disabled].alert{background-color:#f04124;border-color:#cf2a0e;color:#FFFFFF;box-shadow:none;cursor:default;opacity:0.7}button.disabled.alert:hover,button.disabled.alert:focus,button[disabled].alert:hover,button[disabled].alert:focus,.button.disabled.alert:hover,.button.disabled.alert:focus,.button[disabled].alert:hover,.button[disabled].alert:focus{background-color:#cf2a0e}button.disabled.alert:hover,button.disabled.alert:focus,button[disabled].alert:hover,button[disabled].alert:focus,.button.disabled.alert:hover,.button.disabled.alert:focus,.button[disabled].alert:hover,.button[disabled].alert:focus{color:#FFFFFF}button.disabled.alert:hover,button.disabled.alert:focus,button[disabled].alert:hover,button[disabled].alert:focus,.button.disabled.alert:hover,.button.disabled.alert:focus,.button[disabled].alert:hover,.button[disabled].alert:focus{background-color:#f04124}button.disabled.warning,button[disabled].warning,.button.disabled.warning,.button[disabled].warning{background-color:#f08a24;border-color:#cf6e0e;color:#FFFFFF;box-shadow:none;cursor:default;opacity:0.7}button.disabled.warning:hover,button.disabled.warning:focus,button[disabled].warning:hover,button[disabled].warning:focus,.button.disabled.warning:hover,.button.disabled.warning:focus,.button[disabled].warning:hover,.button[disabled].warning:focus{background-color:#cf6e0e}button.disabled.warning:hover,button.disabled.warning:focus,button[disabled].warning:hover,button[disabled].warning:focus,.button.disabled.warning:hover,.button.disabled.warning:focus,.button[disabled].warning:hover,.button[disabled].warning:focus{color:#FFFFFF}button.disabled.warning:hover,button.disabled.warning:focus,button[disabled].warning:hover,button[disabled].warning:focus,.button.disabled.warning:hover,.button.disabled.warning:focus,.button[disabled].warning:hover,.button[disabled].warning:focus{background-color:#f08a24}button.disabled.info,button[disabled].info,.button.disabled.info,.button[disabled].info{background-color:#a0d3e8;border-color:#61b6d9;color:#333333;box-shadow:none;cursor:default;opacity:0.7}button.disabled.info:hover,button.disabled.info:focus,button[disabled].info:hover,button[disabled].info:focus,.button.disabled.info:hover,.button.disabled.info:focus,.button[disabled].info:hover,.button[disabled].info:focus{background-color:#61b6d9}button.disabled.info:hover,button.disabled.info:focus,button[disabled].info:hover,button[disabled].info:focus,.button.disabled.info:hover,.button.disabled.info:focus,.button[disabled].info:hover,.button[disabled].info:focus{color:#FFFFFF}button.disabled.info:hover,button.disabled.info:focus,button[disabled].info:hover,button[disabled].info:focus,.button.disabled.info:hover,.button.disabled.info:focus,.button[disabled].info:hover,.button[disabled].info:focus{background-color:#a0d3e8}button::-moz-focus-inner{border:0;padding:0}@media only screen and (min-width: 40.0625em){button,.button{display:inline-block}}.button-group{list-style:none;margin:0;left:0}.button-group:before,.button-group:after{content:" ";display:table}.button-group:after{clear:both}.button-group.even-2 li{display:inline-block;margin:0 -2px;width:50%}.button-group.even-2 li>button,.button-group.even-2 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-2 li:first-child button,.button-group.even-2 li:first-child .button{border-left:0}.button-group.even-2 li button,.button-group.even-2 li .button{width:100%}.button-group.even-3 li{display:inline-block;margin:0 -2px;width:33.3333333333%}.button-group.even-3 li>button,.button-group.even-3 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-3 li:first-child button,.button-group.even-3 li:first-child .button{border-left:0}.button-group.even-3 li button,.button-group.even-3 li .button{width:100%}.button-group.even-4 li{display:inline-block;margin:0 -2px;width:25%}.button-group.even-4 li>button,.button-group.even-4 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-4 li:first-child button,.button-group.even-4 li:first-child .button{border-left:0}.button-group.even-4 li button,.button-group.even-4 li .button{width:100%}.button-group.even-5 li{display:inline-block;margin:0 -2px;width:20%}.button-group.even-5 li>button,.button-group.even-5 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-5 li:first-child button,.button-group.even-5 li:first-child .button{border-left:0}.button-group.even-5 li button,.button-group.even-5 li .button{width:100%}.button-group.even-6 li{display:inline-block;margin:0 -2px;width:16.6666666667%}.button-group.even-6 li>button,.button-group.even-6 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-6 li:first-child button,.button-group.even-6 li:first-child .button{border-left:0}.button-group.even-6 li button,.button-group.even-6 li .button{width:100%}.button-group.even-7 li{display:inline-block;margin:0 -2px;width:14.2857142857%}.button-group.even-7 li>button,.button-group.even-7 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-7 li:first-child button,.button-group.even-7 li:first-child .button{border-left:0}.button-group.even-7 li button,.button-group.even-7 li .button{width:100%}.button-group.even-8 li{display:inline-block;margin:0 -2px;width:12.5%}.button-group.even-8 li>button,.button-group.even-8 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-8 li:first-child button,.button-group.even-8 li:first-child .button{border-left:0}.button-group.even-8 li button,.button-group.even-8 li .button{width:100%}.button-group>li{display:inline-block;margin:0 -2px}.button-group>li>button,.button-group>li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group>li:first-child button,.button-group>li:first-child .button{border-left:0}.button-group.stack>li{display:block;margin:0;float:none}.button-group.stack>li>button,.button-group.stack>li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.stack>li:first-child button,.button-group.stack>li:first-child .button{border-left:0}.button-group.stack>li>button,.button-group.stack>li .button{border-color:rgba(255,255,255,0.5);border-left-width:0;border-top:1px solid;display:block;margin:0}.button-group.stack>li>button{width:100%}.button-group.stack>li:first-child button,.button-group.stack>li:first-child .button{border-top:0}.button-group.stack-for-small>li{display:inline-block;margin:0 -2px}.button-group.stack-for-small>li>button,.button-group.stack-for-small>li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.stack-for-small>li:first-child button,.button-group.stack-for-small>li:first-child .button{border-left:0}@media only screen and (max-width: 40em){.button-group.stack-for-small>li{display:block;margin:0}.button-group.stack-for-small>li>button,.button-group.stack-for-small>li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.stack-for-small>li:first-child button,.button-group.stack-for-small>li:first-child .button{border-left:0}.button-group.stack-for-small>li>button,.button-group.stack-for-small>li .button{border-color:rgba(255,255,255,0.5);border-left-width:0;border-top:1px solid;display:block;margin:0}.button-group.stack-for-small>li>button{width:100%}.button-group.stack-for-small>li:first-child button,.button-group.stack-for-small>li:first-child .button{border-top:0}}.button-group.radius>*{display:inline-block;margin:0 -2px}.button-group.radius>*>button,.button-group.radius>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.radius>*:first-child button,.button-group.radius>*:first-child .button{border-left:0}.button-group.radius>*,.button-group.radius>*>a,.button-group.radius>*>button,.button-group.radius>*>.button{border-radius:0}.button-group.radius>*:first-child,.button-group.radius>*:first-child>a,.button-group.radius>*:first-child>button,.button-group.radius>*:first-child>.button{-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}.button-group.radius>*:last-child,.button-group.radius>*:last-child>a,.button-group.radius>*:last-child>button,.button-group.radius>*:last-child>.button{-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}.button-group.radius.stack>*{display:block;margin:0}.button-group.radius.stack>*>button,.button-group.radius.stack>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.radius.stack>*:first-child button,.button-group.radius.stack>*:first-child .button{border-left:0}.button-group.radius.stack>*>button,.button-group.radius.stack>* .button{border-color:rgba(255,255,255,0.5);border-left-width:0;border-top:1px solid;display:block;margin:0}.button-group.radius.stack>*>button{width:100%}.button-group.radius.stack>*:first-child button,.button-group.radius.stack>*:first-child .button{border-top:0}.button-group.radius.stack>*,.button-group.radius.stack>*>a,.button-group.radius.stack>*>button,.button-group.radius.stack>*>.button{border-radius:0}.button-group.radius.stack>*:first-child,.button-group.radius.stack>*:first-child>a,.button-group.radius.stack>*:first-child>button,.button-group.radius.stack>*:first-child>.button{-webkit-top-left-radius:3px;-webkit-top-right-radius:3px;border-top-left-radius:3px;border-top-right-radius:3px}.button-group.radius.stack>*:last-child,.button-group.radius.stack>*:last-child>a,.button-group.radius.stack>*:last-child>button,.button-group.radius.stack>*:last-child>.button{-webkit-bottom-left-radius:3px;-webkit-bottom-right-radius:3px;border-bottom-left-radius:3px;border-bottom-right-radius:3px}@media only screen and (min-width: 40.0625em){.button-group.radius.stack-for-small>*{display:inline-block;margin:0 -2px}.button-group.radius.stack-for-small>*>button,.button-group.radius.stack-for-small>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.radius.stack-for-small>*:first-child button,.button-group.radius.stack-for-small>*:first-child .button{border-left:0}.button-group.radius.stack-for-small>*,.button-group.radius.stack-for-small>*>a,.button-group.radius.stack-for-small>*>button,.button-group.radius.stack-for-small>*>.button{border-radius:0}.button-group.radius.stack-for-small>*:first-child,.button-group.radius.stack-for-small>*:first-child>a,.button-group.radius.stack-for-small>*:first-child>button,.button-group.radius.stack-for-small>*:first-child>.button{-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}.button-group.radius.stack-for-small>*:last-child,.button-group.radius.stack-for-small>*:last-child>a,.button-group.radius.stack-for-small>*:last-child>button,.button-group.radius.stack-for-small>*:last-child>.button{-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}}@media only screen and (max-width: 40em){.button-group.radius.stack-for-small>*{display:block;margin:0}.button-group.radius.stack-for-small>*>button,.button-group.radius.stack-for-small>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.radius.stack-for-small>*:first-child button,.button-group.radius.stack-for-small>*:first-child .button{border-left:0}.button-group.radius.stack-for-small>*>button,.button-group.radius.stack-for-small>* .button{border-color:rgba(255,255,255,0.5);border-left-width:0;border-top:1px solid;display:block;margin:0}.button-group.radius.stack-for-small>*>button{width:100%}.button-group.radius.stack-for-small>*:first-child button,.button-group.radius.stack-for-small>*:first-child .button{border-top:0}.button-group.radius.stack-for-small>*,.button-group.radius.stack-for-small>*>a,.button-group.radius.stack-for-small>*>button,.button-group.radius.stack-for-small>*>.button{border-radius:0}.button-group.radius.stack-for-small>*:first-child,.button-group.radius.stack-for-small>*:first-child>a,.button-group.radius.stack-for-small>*:first-child>button,.button-group.radius.stack-for-small>*:first-child>.button{-webkit-top-left-radius:3px;-webkit-top-right-radius:3px;border-top-left-radius:3px;border-top-right-radius:3px}.button-group.radius.stack-for-small>*:last-child,.button-group.radius.stack-for-small>*:last-child>a,.button-group.radius.stack-for-small>*:last-child>button,.button-group.radius.stack-for-small>*:last-child>.button{-webkit-bottom-left-radius:3px;-webkit-bottom-right-radius:3px;border-bottom-left-radius:3px;border-bottom-right-radius:3px}}.button-group.round>*{display:inline-block;margin:0 -2px}.button-group.round>*>button,.button-group.round>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.round>*:first-child button,.button-group.round>*:first-child .button{border-left:0}.button-group.round>*,.button-group.round>*>a,.button-group.round>*>button,.button-group.round>*>.button{border-radius:0}.button-group.round>*:first-child,.button-group.round>*:first-child>a,.button-group.round>*:first-child>button,.button-group.round>*:first-child>.button{-webkit-border-bottom-left-radius:1000px;-webkit-border-top-left-radius:1000px;border-bottom-left-radius:1000px;border-top-left-radius:1000px}.button-group.round>*:last-child,.button-group.round>*:last-child>a,.button-group.round>*:last-child>button,.button-group.round>*:last-child>.button{-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}.button-group.round.stack>*{display:block;margin:0}.button-group.round.stack>*>button,.button-group.round.stack>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.round.stack>*:first-child button,.button-group.round.stack>*:first-child .button{border-left:0}.button-group.round.stack>*>button,.button-group.round.stack>* .button{border-color:rgba(255,255,255,0.5);border-left-width:0;border-top:1px solid;display:block;margin:0}.button-group.round.stack>*>button{width:100%}.button-group.round.stack>*:first-child button,.button-group.round.stack>*:first-child .button{border-top:0}.button-group.round.stack>*,.button-group.round.stack>*>a,.button-group.round.stack>*>button,.button-group.round.stack>*>.button{border-radius:0}.button-group.round.stack>*:first-child,.button-group.round.stack>*:first-child>a,.button-group.round.stack>*:first-child>button,.button-group.round.stack>*:first-child>.button{-webkit-top-left-radius:1rem;-webkit-top-right-radius:1rem;border-top-left-radius:1rem;border-top-right-radius:1rem}.button-group.round.stack>*:last-child,.button-group.round.stack>*:last-child>a,.button-group.round.stack>*:last-child>button,.button-group.round.stack>*:last-child>.button{-webkit-bottom-left-radius:1rem;-webkit-bottom-right-radius:1rem;border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}@media only screen and (min-width: 40.0625em){.button-group.round.stack-for-small>*{display:inline-block;margin:0 -2px}.button-group.round.stack-for-small>*>button,.button-group.round.stack-for-small>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.round.stack-for-small>*:first-child button,.button-group.round.stack-for-small>*:first-child .button{border-left:0}.button-group.round.stack-for-small>*,.button-group.round.stack-for-small>*>a,.button-group.round.stack-for-small>*>button,.button-group.round.stack-for-small>*>.button{border-radius:0}.button-group.round.stack-for-small>*:first-child,.button-group.round.stack-for-small>*:first-child>a,.button-group.round.stack-for-small>*:first-child>button,.button-group.round.stack-for-small>*:first-child>.button{-webkit-border-bottom-left-radius:1000px;-webkit-border-top-left-radius:1000px;border-bottom-left-radius:1000px;border-top-left-radius:1000px}.button-group.round.stack-for-small>*:last-child,.button-group.round.stack-for-small>*:last-child>a,.button-group.round.stack-for-small>*:last-child>button,.button-group.round.stack-for-small>*:last-child>.button{-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}}@media only screen and (max-width: 40em){.button-group.round.stack-for-small>*{display:block;margin:0}.button-group.round.stack-for-small>*>button,.button-group.round.stack-for-small>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.round.stack-for-small>*:first-child button,.button-group.round.stack-for-small>*:first-child .button{border-left:0}.button-group.round.stack-for-small>*>button,.button-group.round.stack-for-small>* .button{border-color:rgba(255,255,255,0.5);border-left-width:0;border-top:1px solid;display:block;margin:0}.button-group.round.stack-for-small>*>button{width:100%}.button-group.round.stack-for-small>*:first-child button,.button-group.round.stack-for-small>*:first-child .button{border-top:0}.button-group.round.stack-for-small>*,.button-group.round.stack-for-small>*>a,.button-group.round.stack-for-small>*>button,.button-group.round.stack-for-small>*>.button{border-radius:0}.button-group.round.stack-for-small>*:first-child,.button-group.round.stack-for-small>*:first-child>a,.button-group.round.stack-for-small>*:first-child>button,.button-group.round.stack-for-small>*:first-child>.button{-webkit-top-left-radius:1rem;-webkit-top-right-radius:1rem;border-top-left-radius:1rem;border-top-right-radius:1rem}.button-group.round.stack-for-small>*:last-child,.button-group.round.stack-for-small>*:last-child>a,.button-group.round.stack-for-small>*:last-child>button,.button-group.round.stack-for-small>*:last-child>.button{-webkit-bottom-left-radius:1rem;-webkit-bottom-right-radius:1rem;border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}}.button-bar:before,.button-bar:after{content:" ";display:table}.button-bar:after{clear:both}.button-bar .button-group{float:left;margin-right:0.625rem}.button-bar .button-group div{overflow:hidden}.clearing-thumbs,[data-clearing]{list-style:none;margin-left:0;margin-bottom:0}.clearing-thumbs:before,.clearing-thumbs:after,[data-clearing]:before,[data-clearing]:after{content:" ";display:table}.clearing-thumbs:after,[data-clearing]:after{clear:both}.clearing-thumbs li,[data-clearing] li{float:left;margin-right:10px}.clearing-thumbs[class*="block-grid-"] li,[data-clearing][class*="block-grid-"] li{margin-right:0}.clearing-blackout{background:#333333;height:100%;position:fixed;top:0;width:100%;z-index:998;left:0}.clearing-blackout .clearing-close{display:block}.clearing-container{height:100%;margin:0;overflow:hidden;position:relative;z-index:998}.clearing-touch-label{color:#AAAAAA;font-size:.6em;left:50%;position:absolute;top:50%}.visible-img{height:95%;position:relative}.visible-img img{position:absolute;left:50%;top:50%;-webkit-transform:translateY(-50%) translateX(-50%);-moz-transform:translateY(-50%) translateX(-50%);-ms-transform:translateY(-50%) translateX(-50%);-o-transform:translateY(-50%) translateX(-50%);transform:translateY(-50%) translateX(-50%);max-height:100%;max-width:100%}.clearing-caption{background:#333333;bottom:0;color:#CCCCCC;font-size:0.875em;line-height:1.3;margin-bottom:0;padding:10px 30px 20px;position:absolute;text-align:center;width:100%;left:0}.clearing-close{color:#CCCCCC;display:none;font-size:30px;line-height:1;padding-left:20px;padding-top:10px;z-index:999}.clearing-close:hover,.clearing-close:focus{color:#CCCCCC}.clearing-assembled .clearing-container{height:100%}.clearing-assembled .clearing-container .carousel>ul{display:none}.clearing-feature li{display:none}.clearing-feature li.clearing-featured-img{display:block}@media only screen and (min-width: 40.0625em){.clearing-main-prev,.clearing-main-next{height:100%;position:absolute;top:0;width:40px}.clearing-main-prev>span,.clearing-main-next>span{border:solid 12px;display:block;height:0;position:absolute;top:50%;width:0}.clearing-main-prev>span:hover,.clearing-main-next>span:hover{opacity:.8}.clearing-main-prev{left:0}.clearing-main-prev>span{left:5px;border-color:transparent;border-right-color:#CCCCCC}.clearing-main-next{right:0}.clearing-main-next>span{border-color:transparent;border-left-color:#CCCCCC}.clearing-main-prev.disabled,.clearing-main-next.disabled{opacity:.3}.clearing-assembled .clearing-container .carousel{background:rgba(51,51,51,0.8);height:120px;margin-top:10px;text-align:center}.clearing-assembled .clearing-container .carousel>ul{display:inline-block;z-index:999;height:100%;position:relative;float:none}.clearing-assembled .clearing-container .carousel>ul li{clear:none;cursor:pointer;display:block;float:left;margin-right:0;min-height:inherit;opacity:.4;overflow:hidden;padding:0;position:relative;width:120px}.clearing-assembled .clearing-container .carousel>ul li.fix-height img{height:100%;max-width:none}.clearing-assembled .clearing-container .carousel>ul li a.th{border:none;box-shadow:none;display:block}.clearing-assembled .clearing-container .carousel>ul li img{cursor:pointer !important;width:100% !important}.clearing-assembled .clearing-container .carousel>ul li.visible{opacity:1}.clearing-assembled .clearing-container .carousel>ul li:hover{opacity:.8}.clearing-assembled .clearing-container .visible-img{background:#333333;height:85%;overflow:hidden}.clearing-close{padding-left:0;padding-top:0;position:absolute;top:10px;right:20px}}.f-dropdown{display:none;left:-9999px;list-style:none;margin-left:0;position:absolute;background:#FFFFFF;border:solid 1px #cccccc;font-size:0.875rem;height:auto;max-height:none;width:100%;z-index:89;margin-top:2px;max-width:200px}.f-dropdown.open{display:block}.f-dropdown>*:first-child{margin-top:0}.f-dropdown>*:last-child{margin-bottom:0}.f-dropdown:before{border:inset 6px;content:"";display:block;height:0;width:0;border-color:transparent transparent #FFFFFF transparent;border-bottom-style:solid;position:absolute;top:-12px;left:10px;z-index:89}.f-dropdown:after{border:inset 7px;content:"";display:block;height:0;width:0;border-color:transparent transparent #cccccc transparent;border-bottom-style:solid;position:absolute;top:-14px;left:9px;z-index:88}.f-dropdown.right:before{left:auto;right:10px}.f-dropdown.right:after{left:auto;right:9px}.f-dropdown.drop-right{display:none;left:-9999px;list-style:none;margin-left:0;position:absolute;background:#FFFFFF;border:solid 1px #cccccc;font-size:0.875rem;height:auto;max-height:none;width:100%;z-index:89;margin-top:0;margin-left:2px;max-width:200px}.f-dropdown.drop-right.open{display:block}.f-dropdown.drop-right>*:first-child{margin-top:0}.f-dropdown.drop-right>*:last-child{margin-bottom:0}.f-dropdown.drop-right:before{border:inset 6px;content:"";display:block;height:0;width:0;border-color:transparent #FFFFFF transparent transparent;border-right-style:solid;position:absolute;top:10px;left:-12px;z-index:89}.f-dropdown.drop-right:after{border:inset 7px;content:"";display:block;height:0;width:0;border-color:transparent #cccccc transparent transparent;border-right-style:solid;position:absolute;top:9px;left:-14px;z-index:88}.f-dropdown.drop-left{display:none;left:-9999px;list-style:none;margin-left:0;position:absolute;background:#FFFFFF;border:solid 1px #cccccc;font-size:0.875rem;height:auto;max-height:none;width:100%;z-index:89;margin-top:0;margin-left:-2px;max-width:200px}.f-dropdown.drop-left.open{display:block}.f-dropdown.drop-left>*:first-child{margin-top:0}.f-dropdown.drop-left>*:last-child{margin-bottom:0}.f-dropdown.drop-left:before{border:inset 6px;content:"";display:block;height:0;width:0;border-color:transparent transparent transparent #FFFFFF;border-left-style:solid;position:absolute;top:10px;right:-12px;left:auto;z-index:89}.f-dropdown.drop-left:after{border:inset 7px;content:"";display:block;height:0;width:0;border-color:transparent transparent transparent #cccccc;border-left-style:solid;position:absolute;top:9px;right:-14px;left:auto;z-index:88}.f-dropdown.drop-top{display:none;left:-9999px;list-style:none;margin-left:0;position:absolute;background:#FFFFFF;border:solid 1px #cccccc;font-size:0.875rem;height:auto;max-height:none;width:100%;z-index:89;margin-left:0;margin-top:-2px;max-width:200px}.f-dropdown.drop-top.open{display:block}.f-dropdown.drop-top>*:first-child{margin-top:0}.f-dropdown.drop-top>*:last-child{margin-bottom:0}.f-dropdown.drop-top:before{border:inset 6px;content:"";display:block;height:0;width:0;border-color:#FFFFFF transparent transparent transparent;border-top-style:solid;bottom:-12px;position:absolute;top:auto;left:10px;right:auto;z-index:89}.f-dropdown.drop-top:after{border:inset 7px;content:"";display:block;height:0;width:0;border-color:#cccccc transparent transparent transparent;border-top-style:solid;bottom:-14px;position:absolute;top:auto;left:9px;right:auto;z-index:88}.f-dropdown li{cursor:pointer;font-size:0.875rem;line-height:1.125rem;margin:0}.f-dropdown li:hover,.f-dropdown li:focus{background:#EEEEEE}.f-dropdown li.radius{border-radius:3px}.f-dropdown li a{display:block;padding:0.5rem;color:#555555}.f-dropdown.content{display:none;left:-9999px;list-style:none;margin-left:0;position:absolute;background:#FFFFFF;border:solid 1px #cccccc;font-size:0.875rem;height:auto;max-height:none;padding:1.25rem;width:100%;z-index:89;max-width:200px}.f-dropdown.content.open{display:block}.f-dropdown.content>*:first-child{margin-top:0}.f-dropdown.content>*:last-child{margin-bottom:0}.f-dropdown.tiny{max-width:200px}.f-dropdown.small{max-width:300px}.f-dropdown.medium{max-width:500px}.f-dropdown.large{max-width:800px}.f-dropdown.mega{width:100% !important;max-width:100% !important}.f-dropdown.mega.open{left:0 !important}.dropdown.button,button.dropdown{position:relative;padding-right:3.5625rem}.dropdown.button::after,button.dropdown::after{border-color:#FFFFFF transparent transparent transparent;border-style:solid;content:"";display:block;height:0;position:absolute;top:50%;width:0}.dropdown.button::after,button.dropdown::after{border-width:0.375rem;right:1.40625rem;margin-top:-0.15625rem}.dropdown.button::after,button.dropdown::after{border-color:#FFFFFF transparent transparent transparent}.dropdown.button.tiny,button.dropdown.tiny{padding-right:2.625rem}.dropdown.button.tiny:after,button.dropdown.tiny:after{border-width:0.375rem;right:1.125rem;margin-top:-0.125rem}.dropdown.button.tiny::after,button.dropdown.tiny::after{border-color:#FFFFFF transparent transparent transparent}.dropdown.button.small,button.dropdown.small{padding-right:3.0625rem}.dropdown.button.small::after,button.dropdown.small::after{border-width:0.4375rem;right:1.3125rem;margin-top:-0.15625rem}.dropdown.button.small::after,button.dropdown.small::after{border-color:#FFFFFF transparent transparent transparent}.dropdown.button.large,button.dropdown.large{padding-right:3.625rem}.dropdown.button.large::after,button.dropdown.large::after{border-width:0.3125rem;right:1.71875rem;margin-top:-0.15625rem}.dropdown.button.large::after,button.dropdown.large::after{border-color:#FFFFFF transparent transparent transparent}.dropdown.button.secondary:after,button.dropdown.secondary:after{border-color:#333333 transparent transparent transparent}.flex-video{height:0;margin-bottom:1rem;overflow:hidden;padding-bottom:67.5%;padding-top:1.5625rem;position:relative}.flex-video.widescreen{padding-bottom:56.34%}.flex-video.vimeo{padding-top:0}.flex-video iframe,.flex-video object,.flex-video embed,.flex-video video{height:100%;position:absolute;top:0;width:100%;left:0}form{margin:0 0 1rem}form .row .row{margin:0 -0.5rem}form .row .row .column,form .row .row .columns{padding:0 0.5rem}form .row .row.collapse{margin:0}form .row .row.collapse .column,form .row .row.collapse .columns{padding:0}form .row .row.collapse input{-webkit-border-bottom-right-radius:0;-webkit-border-top-right-radius:0;border-bottom-right-radius:0;border-top-right-radius:0}form .row input.column,form .row input.columns,form .row textarea.column,form .row textarea.columns{padding-left:0.5rem}label{color:#4d4d4d;cursor:pointer;display:block;font-size:0.875rem;font-weight:normal;line-height:1.5;margin-bottom:0}label.right{float:none !important;text-align:right}label.inline{margin:0 0 1rem 0;padding:0.5625rem 0}label small{text-transform:capitalize;color:#676767}.prefix,.postfix{border-style:solid;border-width:1px;display:block;font-size:0.875rem;height:2.3125rem;line-height:2.3125rem;overflow:visible;padding-bottom:0;padding-top:0;position:relative;text-align:center;width:100%;z-index:2}.postfix.button{border-color:true}.prefix.button{border:none;padding-left:0;padding-right:0;padding-bottom:0;padding-top:0;text-align:center}.prefix.button.radius{border-radius:0;-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}.postfix.button.radius{border-radius:0;-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}.prefix.button.round{border-radius:0;-webkit-border-bottom-left-radius:1000px;-webkit-border-top-left-radius:1000px;border-bottom-left-radius:1000px;border-top-left-radius:1000px}.postfix.button.round{border-radius:0;-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}span.prefix,label.prefix{background:#f2f2f2;border-right:none;color:#333333;border-color:#cccccc}span.postfix,label.postfix{background:#f2f2f2;color:#333333;border-color:#cccccc}input[type="text"],input[type="password"],input[type="date"],input[type="datetime"],input[type="datetime-local"],input[type="month"],input[type="week"],input[type="email"],input[type="number"],input[type="search"],input[type="tel"],input[type="time"],input[type="url"],input[type="color"],textarea{-webkit-appearance:none;-moz-appearance:none;border-radius:0;background-color:#FFFFFF;border-style:solid;border-width:1px;border-color:#cccccc;box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);color:rgba(0,0,0,0.75);display:block;font-family:inherit;font-size:0.875rem;height:2.3125rem;margin:0 0 1rem 0;padding:0.5rem;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color 0.15s linear, background 0.15s linear;-moz-transition:border-color 0.15s linear, background 0.15s linear;-ms-transition:border-color 0.15s linear, background 0.15s linear;-o-transition:border-color 0.15s linear, background 0.15s linear;transition:border-color 0.15s linear, background 0.15s linear}input[type="text"]:focus,input[type="password"]:focus,input[type="date"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="month"]:focus,input[type="week"]:focus,input[type="email"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="time"]:focus,input[type="url"]:focus,input[type="color"]:focus,textarea:focus{background:#fafafa;border-color:#999999;outline:none}input[type="text"]:disabled,input[type="password"]:disabled,input[type="date"]:disabled,input[type="datetime"]:disabled,input[type="datetime-local"]:disabled,input[type="month"]:disabled,input[type="week"]:disabled,input[type="email"]:disabled,input[type="number"]:disabled,input[type="search"]:disabled,input[type="tel"]:disabled,input[type="time"]:disabled,input[type="url"]:disabled,input[type="color"]:disabled,textarea:disabled{background-color:#DDDDDD;cursor:default}input[type="text"][disabled],input[type="text"][readonly],fieldset[disabled] input[type="text"],input[type="password"][disabled],input[type="password"][readonly],fieldset[disabled] input[type="password"],input[type="date"][disabled],input[type="date"][readonly],fieldset[disabled] input[type="date"],input[type="datetime"][disabled],input[type="datetime"][readonly],fieldset[disabled] input[type="datetime"],input[type="datetime-local"][disabled],input[type="datetime-local"][readonly],fieldset[disabled] input[type="datetime-local"],input[type="month"][disabled],input[type="month"][readonly],fieldset[disabled] input[type="month"],input[type="week"][disabled],input[type="week"][readonly],fieldset[disabled] input[type="week"],input[type="email"][disabled],input[type="email"][readonly],fieldset[disabled] input[type="email"],input[type="number"][disabled],input[type="number"][readonly],fieldset[disabled] input[type="number"],input[type="search"][disabled],input[type="search"][readonly],fieldset[disabled] input[type="search"],input[type="tel"][disabled],input[type="tel"][readonly],fieldset[disabled] input[type="tel"],input[type="time"][disabled],input[type="time"][readonly],fieldset[disabled] input[type="time"],input[type="url"][disabled],input[type="url"][readonly],fieldset[disabled] input[type="url"],input[type="color"][disabled],input[type="color"][readonly],fieldset[disabled] input[type="color"],textarea[disabled],textarea[readonly],fieldset[disabled] textarea{background-color:#DDDDDD;cursor:default}input[type="text"].radius,input[type="password"].radius,input[type="date"].radius,input[type="datetime"].radius,input[type="datetime-local"].radius,input[type="month"].radius,input[type="week"].radius,input[type="email"].radius,input[type="number"].radius,input[type="search"].radius,input[type="tel"].radius,input[type="time"].radius,input[type="url"].radius,input[type="color"].radius,textarea.radius{border-radius:3px}form .row .prefix-radius.row.collapse input,form .row .prefix-radius.row.collapse textarea,form .row .prefix-radius.row.collapse select,form .row .prefix-radius.row.collapse button{border-radius:0;-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}form .row .prefix-radius.row.collapse .prefix{border-radius:0;-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}form .row .postfix-radius.row.collapse input,form .row .postfix-radius.row.collapse textarea,form .row .postfix-radius.row.collapse select,form .row .postfix-radius.row.collapse button{border-radius:0;-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}form .row .postfix-radius.row.collapse .postfix{border-radius:0;-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}form .row .prefix-round.row.collapse input,form .row .prefix-round.row.collapse textarea,form .row .prefix-round.row.collapse select,form .row .prefix-round.row.collapse button{border-radius:0;-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}form .row .prefix-round.row.collapse .prefix{border-radius:0;-webkit-border-bottom-left-radius:1000px;-webkit-border-top-left-radius:1000px;border-bottom-left-radius:1000px;border-top-left-radius:1000px}form .row .postfix-round.row.collapse input,form .row .postfix-round.row.collapse textarea,form .row .postfix-round.row.collapse select,form .row .postfix-round.row.collapse button{border-radius:0;-webkit-border-bottom-left-radius:1000px;-webkit-border-top-left-radius:1000px;border-bottom-left-radius:1000px;border-top-left-radius:1000px}form .row .postfix-round.row.collapse .postfix{border-radius:0;-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}input[type="submit"]{-webkit-appearance:none;-moz-appearance:none;border-radius:0}textarea[rows]{height:auto}textarea{max-width:100%}::-webkit-input-placeholder{color:#cccccc}:-moz-placeholder{color:#cccccc}::-moz-placeholder{color:#cccccc}:-ms-input-placeholder{color:#cccccc}select{-webkit-appearance:none !important;-moz-appearance:none !important;background-color:#FAFAFA;border-radius:0;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeD0iMTJweCIgeT0iMHB4IiB3aWR0aD0iMjRweCIgaGVpZ2h0PSIzcHgiIHZpZXdCb3g9IjAgMCA2IDMiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDYgMyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHBvbHlnb24gcG9pbnRzPSI1Ljk5MiwwIDIuOTkyLDMgLTAuMDA4LDAgIi8+PC9zdmc+);background-position:100% center;background-repeat:no-repeat;border-style:solid;border-width:1px;border-color:#cccccc;color:rgba(0,0,0,0.75);font-family:inherit;font-size:0.875rem;line-height:normal;padding:0.5rem;border-radius:0;height:2.3125rem}select::-ms-expand{display:none}select.radius{border-radius:3px}select:hover{background-color:#f3f3f3;border-color:#999999}select:disabled{background-color:#DDDDDD;cursor:default}select[multiple]{height:auto}input[type="file"],input[type="checkbox"],input[type="radio"],select{margin:0 0 1rem 0}input[type="checkbox"]+label,input[type="radio"]+label{display:inline-block;margin-left:0.5rem;margin-right:1rem;margin-bottom:0;vertical-align:baseline}input[type="file"]{width:100%}fieldset{border:1px solid #DDDDDD;margin:1.125rem 0;padding:1.25rem}fieldset legend{background:#FFFFFF;font-weight:bold;margin-left:-0.1875rem;margin:0;padding:0 0.1875rem}[data-abide] .error small.error,[data-abide] .error span.error,[data-abide] span.error,[data-abide] small.error{display:block;font-size:0.75rem;font-style:italic;font-weight:normal;margin-bottom:1rem;margin-top:-1px;padding:0.375rem 0.5625rem 0.5625rem;background:#f04124;color:#FFFFFF}[data-abide] span.error,[data-abide] small.error{display:none}span.error,small.error{display:block;font-size:0.75rem;font-style:italic;font-weight:normal;margin-bottom:1rem;margin-top:-1px;padding:0.375rem 0.5625rem 0.5625rem;background:#f04124;color:#FFFFFF}.error input,.error textarea,.error select{margin-bottom:0}.error input[type="checkbox"],.error input[type="radio"]{margin-bottom:1rem}.error label,.error label.error{color:#f04124}.error small.error{display:block;font-size:0.75rem;font-style:italic;font-weight:normal;margin-bottom:1rem;margin-top:-1px;padding:0.375rem 0.5625rem 0.5625rem;background:#f04124;color:#FFFFFF}.error>label>small{background:transparent;color:#676767;display:inline;font-size:60%;font-style:normal;margin:0;padding:0;text-transform:capitalize}.error span.error-message{display:block}input.error,textarea.error,select.error{margin-bottom:0}label.error{color:#f04124}.icon-bar{display:inline-block;font-size:0;width:100%;background:#333333}.icon-bar>*{display:block;float:left;font-size:1rem;margin:0 auto;padding:1.25rem;text-align:center;width:25%}.icon-bar>* i,.icon-bar>* img{display:block;margin:0 auto}.icon-bar>* i+label,.icon-bar>* img+label{margin-top:.0625rem}.icon-bar>* i{font-size:1.875rem;vertical-align:middle}.icon-bar>* img{height:1.875rem;width:1.875rem}.icon-bar.label-right>* i,.icon-bar.label-right>* img{display:inline-block;margin:0 .0625rem 0 0}.icon-bar.label-right>* i+label,.icon-bar.label-right>* img+label{margin-top:0}.icon-bar.label-right>* label{display:inline-block}.icon-bar.vertical.label-right>*{text-align:left}.icon-bar.vertical,.icon-bar.small-vertical{height:100%;width:auto}.icon-bar.vertical .item,.icon-bar.small-vertical .item{float:none;margin:auto;width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.medium-vertical{height:100%;width:auto}.icon-bar.medium-vertical .item{float:none;margin:auto;width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.large-vertical{height:100%;width:auto}.icon-bar.large-vertical .item{float:none;margin:auto;width:auto}}.icon-bar>*{font-size:1rem;padding:1.25rem}.icon-bar>* i+label,.icon-bar>* img+label{margin-top:.0625rem;font-size:1rem}.icon-bar>* i{font-size:1.875rem}.icon-bar>* img{height:1.875rem;width:1.875rem}.icon-bar>* label{color:#FFFFFF}.icon-bar>* i{color:#FFFFFF}.icon-bar>a:hover{background:#008CBA}.icon-bar>a:hover label{color:#FFFFFF}.icon-bar>a:hover i{color:#FFFFFF}.icon-bar>a.active{background:#008CBA}.icon-bar>a.active label{color:#FFFFFF}.icon-bar>a.active i{color:#FFFFFF}.icon-bar .item.disabled{cursor:not-allowed;opacity:0.7;pointer-events:none}.icon-bar .item.disabled>*{opacity:0.7;cursor:not-allowed}.icon-bar.two-up .item{width:50%}.icon-bar.two-up.vertical .item,.icon-bar.two-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.two-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.two-up.large-vertical .item{width:auto}}.icon-bar.three-up .item{width:33.3333%}.icon-bar.three-up.vertical .item,.icon-bar.three-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.three-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.three-up.large-vertical .item{width:auto}}.icon-bar.four-up .item{width:25%}.icon-bar.four-up.vertical .item,.icon-bar.four-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.four-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.four-up.large-vertical .item{width:auto}}.icon-bar.five-up .item{width:20%}.icon-bar.five-up.vertical .item,.icon-bar.five-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.five-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.five-up.large-vertical .item{width:auto}}.icon-bar.six-up .item{width:16.66667%}.icon-bar.six-up.vertical .item,.icon-bar.six-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.six-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.six-up.large-vertical .item{width:auto}}.icon-bar.seven-up .item{width:14.28571%}.icon-bar.seven-up.vertical .item,.icon-bar.seven-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.seven-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.seven-up.large-vertical .item{width:auto}}.icon-bar.eight-up .item{width:12.5%}.icon-bar.eight-up.vertical .item,.icon-bar.eight-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.eight-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.eight-up.large-vertical .item{width:auto}}.icon-bar.two-up .item{width:50%}.icon-bar.two-up.vertical .item,.icon-bar.two-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.two-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.two-up.large-vertical .item{width:auto}}.icon-bar.three-up .item{width:33.3333%}.icon-bar.three-up.vertical .item,.icon-bar.three-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.three-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.three-up.large-vertical .item{width:auto}}.icon-bar.four-up .item{width:25%}.icon-bar.four-up.vertical .item,.icon-bar.four-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.four-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.four-up.large-vertical .item{width:auto}}.icon-bar.five-up .item{width:20%}.icon-bar.five-up.vertical .item,.icon-bar.five-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.five-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.five-up.large-vertical .item{width:auto}}.icon-bar.six-up .item{width:16.66667%}.icon-bar.six-up.vertical .item,.icon-bar.six-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.six-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.six-up.large-vertical .item{width:auto}}.icon-bar.seven-up .item{width:14.28571%}.icon-bar.seven-up.vertical .item,.icon-bar.seven-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.seven-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.seven-up.large-vertical .item{width:auto}}.icon-bar.eight-up .item{width:12.5%}.icon-bar.eight-up.vertical .item,.icon-bar.eight-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.0625em){.icon-bar.eight-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.0625em){.icon-bar.eight-up.large-vertical .item{width:auto}}.inline-list{list-style:none;margin-left:-1.375rem;margin-right:0;margin:0 auto 1.0625rem auto;overflow:hidden;padding:0}.inline-list>li{display:block;float:left;list-style:none;margin-left:1.375rem}.inline-list>li>*{display:block}.joyride-list{display:none}.joyride-tip-guide{background:#333333;color:#FFFFFF;display:none;font-family:inherit;font-weight:normal;position:absolute;top:0;width:95%;z-index:101;left:2.5%}.lt-ie9 .joyride-tip-guide{margin-left:-400px;max-width:800px;left:50%}.joyride-content-wrapper{padding:1.125rem 1.25rem 1.5rem;width:100%}.joyride-content-wrapper .button{margin-bottom:0 !important}.joyride-content-wrapper .joyride-prev-tip{margin-right:10px}.joyride-tip-guide .joyride-nub{border:10px solid #333333;display:block;height:0;position:absolute;width:0;left:22px}.joyride-tip-guide .joyride-nub.top{border-color:#333333;border-top-color:transparent !important;border-top-style:solid;border-left-color:transparent !important;border-right-color:transparent !important;top:-20px}.joyride-tip-guide .joyride-nub.bottom{border-color:#333333 !important;border-bottom-color:transparent !important;border-bottom-style:solid;border-left-color:transparent !important;border-right-color:transparent !important;bottom:-20px}.joyride-tip-guide .joyride-nub.right{right:-20px}.joyride-tip-guide .joyride-nub.left{left:-20px}.joyride-tip-guide h1,.joyride-tip-guide h2,.joyride-tip-guide h3,.joyride-tip-guide h4,.joyride-tip-guide h5,.joyride-tip-guide h6{color:#FFFFFF;font-weight:bold;line-height:1.25;margin:0}.joyride-tip-guide p{font-size:0.875rem;line-height:1.3;margin:0 0 1.125rem 0}.joyride-timer-indicator-wrap{border:solid 1px #555555;bottom:1rem;height:3px;position:absolute;width:50px;right:1.0625rem}.joyride-timer-indicator{background:#666666;display:block;height:inherit;width:0}.joyride-close-tip{color:#777777 !important;font-size:24px;font-weight:normal;line-height:.5 !important;position:absolute;text-decoration:none;top:10px;right:12px}.joyride-close-tip:hover,.joyride-close-tip:focus{color:#EEEEEE !important}.joyride-modal-bg{background:rgba(0,0,0,0.5);cursor:pointer;display:none;height:100%;position:fixed;top:0;width:100%;z-index:100;left:0}.joyride-expose-wrapper{background-color:#FFFFFF;border-radius:3px;box-shadow:0 0 15px #FFFFFF;position:absolute;z-index:102}.joyride-expose-cover{background:transparent;border-radius:3px;left:0;position:absolute;top:0;z-index:9999}@media only screen and (min-width: 40.0625em){.joyride-tip-guide{width:300px;left:inherit}.joyride-tip-guide .joyride-nub.bottom{border-color:#333333 !important;border-bottom-color:transparent !important;border-left-color:transparent !important;border-right-color:transparent !important;bottom:-20px}.joyride-tip-guide .joyride-nub.right{border-color:#333333 !important;border-right-color:transparent !important;border-bottom-color:transparent !important;border-top-color:transparent !important;left:auto;right:-20px;top:22px}.joyride-tip-guide .joyride-nub.left{border-color:#333333 !important;border-bottom-color:transparent !important;border-left-color:transparent !important;border-top-color:transparent !important;left:-20px;right:auto;top:22px}}.keystroke,kbd{background-color:#ededed;border-color:#dddddd;color:#222222;border-style:solid;border-width:1px;font-family:"Consolas", "Menlo", "Courier", monospace;font-size:inherit;margin:0;padding:0.125rem 0.25rem 0;border-radius:3px}.label{display:inline-block;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-weight:normal;line-height:1;margin-bottom:auto;position:relative;text-align:center;text-decoration:none;white-space:nowrap;padding:0.25rem 0.5rem 0.25rem;font-size:0.6875rem;background-color:#008CBA;color:#FFFFFF}.label.radius{border-radius:3px}.label.round{border-radius:1000px}.label.alert{background-color:#f04124;color:#FFFFFF}.label.warning{background-color:#f08a24;color:#FFFFFF}.label.success{background-color:#43AC6A;color:#FFFFFF}.label.secondary{background-color:#e7e7e7;color:#333333}.label.info{background-color:#a0d3e8;color:#333333}[data-magellan-expedition],[data-magellan-expedition-clone]{background:#FFFFFF;min-width:100%;padding:10px;z-index:50}[data-magellan-expedition] .sub-nav,[data-magellan-expedition-clone] .sub-nav{margin-bottom:0}[data-magellan-expedition] .sub-nav dd,[data-magellan-expedition-clone] .sub-nav dd{margin-bottom:0}[data-magellan-expedition] .sub-nav a,[data-magellan-expedition-clone] .sub-nav a{line-height:1.8em}@-webkit-keyframes rotate{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotate{from{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}.slideshow-wrapper{position:relative}.slideshow-wrapper ul{list-style-type:none;margin:0}.slideshow-wrapper ul li,.slideshow-wrapper ul li .orbit-caption{display:none}.slideshow-wrapper ul li:first-child{display:block}.slideshow-wrapper .orbit-container{background-color:transparent}.slideshow-wrapper .orbit-container li{display:block}.slideshow-wrapper .orbit-container li .orbit-caption{display:block}.slideshow-wrapper .orbit-container .orbit-bullets li{display:inline-block}.slideshow-wrapper .preloader{border-radius:1000px;animation-duration:1.5s;animation-iteration-count:infinite;animation-name:rotate;animation-timing-function:linear;border-color:#555555 #FFFFFF;border:solid 3px;display:block;height:40px;left:50%;margin-left:-20px;margin-top:-20px;position:absolute;top:50%;width:40px}.orbit-container{background:none;overflow:hidden;position:relative;width:100%}.orbit-container .orbit-slides-container{list-style:none;margin:0;padding:0;position:relative;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}.orbit-container .orbit-slides-container img{display:block;max-width:100%}.orbit-container .orbit-slides-container>*{position:absolute;top:0;width:100%;margin-left:100%}.orbit-container .orbit-slides-container>*:first-child{margin-left:0}.orbit-container .orbit-slides-container>* .orbit-caption{bottom:0;position:absolute;background-color:rgba(51,51,51,0.8);color:#FFFFFF;font-size:0.875rem;padding:0.625rem 0.875rem;width:100%}.orbit-container .orbit-slide-number{left:10px;background:transparent;color:#FFFFFF;font-size:12px;position:absolute;top:10px;z-index:10}.orbit-container .orbit-slide-number span{font-weight:700;padding:0.3125rem}.orbit-container .orbit-timer{position:absolute;top:12px;right:10px;height:6px;width:100px;z-index:10}.orbit-container .orbit-timer .orbit-progress{height:3px;background-color:rgba(255,255,255,0.3);display:block;width:0;position:relative;right:20px;top:5px}.orbit-container .orbit-timer>span{border:solid 4px #FFFFFF;border-bottom:none;border-top:none;display:none;height:14px;position:absolute;top:0;width:11px;right:0}.orbit-container .orbit-timer.paused>span{top:0;width:11px;height:14px;border:inset 8px;border-left-style:solid;border-color:transparent;border-left-color:#FFFFFF;right:-4px}.orbit-container .orbit-timer.paused>span.dark{border-left-color:#333333}.orbit-container:hover .orbit-timer>span{display:block}.orbit-container .orbit-prev,.orbit-container .orbit-next{background-color:transparent;color:white;height:60px;line-height:50px;margin-top:-25px;position:absolute;text-indent:-9999px !important;top:45%;width:36px;z-index:10}.orbit-container .orbit-prev:hover,.orbit-container .orbit-next:hover{background-color:rgba(0,0,0,0.3)}.orbit-container .orbit-prev>span,.orbit-container .orbit-next>span{border:inset 10px;display:block;height:0;margin-top:-10px;position:absolute;top:50%;width:0}.orbit-container .orbit-prev{left:0}.orbit-container .orbit-prev>span{border-right-style:solid;border-color:transparent;border-right-color:#FFFFFF}.orbit-container .orbit-prev:hover>span{border-right-color:#FFFFFF}.orbit-container .orbit-next{right:0}.orbit-container .orbit-next>span{border-color:transparent;border-left-style:solid;border-left-color:#FFFFFF;left:50%;margin-left:-4px}.orbit-container .orbit-next:hover>span{border-left-color:#FFFFFF}.orbit-bullets-container{text-align:center}.orbit-bullets{display:block;float:none;margin:0 auto 30px auto;overflow:hidden;position:relative;text-align:center;top:10px}.orbit-bullets li{background:#CCCCCC;cursor:pointer;display:inline-block;float:none;height:0.5625rem;margin-right:6px;width:0.5625rem;border-radius:1000px}.orbit-bullets li.active{background:#999999}.orbit-bullets li:last-child{margin-right:0}.touch .orbit-container .orbit-prev,.touch .orbit-container .orbit-next{display:none}.touch .orbit-bullets{display:none}@media only screen and (min-width: 40.0625em){.touch .orbit-container .orbit-prev,.touch .orbit-container .orbit-next{display:inherit}.touch .orbit-bullets{display:block}}@media only screen and (max-width: 40em){.orbit-stack-on-small .orbit-slides-container{height:auto !important}.orbit-stack-on-small .orbit-slides-container>*{margin:0 !important;opacity:1 !important;position:relative}.orbit-stack-on-small .orbit-slide-number{display:none}.orbit-timer{display:none}.orbit-next,.orbit-prev{display:none}.orbit-bullets{display:none}}ul.pagination{display:block;margin-left:-0.3125rem;min-height:1.5rem}ul.pagination li{color:#222222;font-size:0.875rem;height:1.5rem;margin-left:0.3125rem}ul.pagination li a,ul.pagination li button{border-radius:3px;transition:background-color 300ms ease-out;background:none;color:#999999;display:block;font-size:1em;font-weight:normal;line-height:inherit;padding:0.0625rem 0.625rem 0.0625rem}ul.pagination li:hover a,ul.pagination li a:focus,ul.pagination li:hover button,ul.pagination li button:focus{background:#e6e6e6}ul.pagination li.unavailable a,ul.pagination li.unavailable button{cursor:default;color:#999999}ul.pagination li.unavailable:hover a,ul.pagination li.unavailable a:focus,ul.pagination li.unavailable:hover button,ul.pagination li.unavailable button:focus{background:transparent}ul.pagination li.current a,ul.pagination li.current button{background:#008CBA;color:#FFFFFF;cursor:default;font-weight:bold}ul.pagination li.current a:hover,ul.pagination li.current a:focus,ul.pagination li.current button:hover,ul.pagination li.current button:focus{background:#008CBA}ul.pagination li{display:block;float:left}.pagination-centered{text-align:center}.pagination-centered ul.pagination li{display:inline-block;float:none}.panel{border-style:solid;border-width:1px;border-color:#d8d8d8;margin-bottom:1.25rem;padding:1.25rem;background:#f2f2f2;color:#333333}.panel>:first-child{margin-top:0}.panel>:last-child{margin-bottom:0}.panel h1,.panel h2,.panel h3,.panel h4,.panel h5,.panel h6,.panel p,.panel li,.panel dl{color:#333333}.panel h1,.panel h2,.panel h3,.panel h4,.panel h5,.panel h6{line-height:1;margin-bottom:0.625rem}.panel h1.subheader,.panel h2.subheader,.panel h3.subheader,.panel h4.subheader,.panel h5.subheader,.panel h6.subheader{line-height:1.4}.panel.callout{border-style:solid;border-width:1px;border-color:#d8d8d8;margin-bottom:1.25rem;padding:1.25rem;background:#ecfaff;color:#333333}.panel.callout>:first-child{margin-top:0}.panel.callout>:last-child{margin-bottom:0}.panel.callout h1,.panel.callout h2,.panel.callout h3,.panel.callout h4,.panel.callout h5,.panel.callout h6,.panel.callout p,.panel.callout li,.panel.callout dl{color:#333333}.panel.callout h1,.panel.callout h2,.panel.callout h3,.panel.callout h4,.panel.callout h5,.panel.callout h6{line-height:1;margin-bottom:0.625rem}.panel.callout h1.subheader,.panel.callout h2.subheader,.panel.callout h3.subheader,.panel.callout h4.subheader,.panel.callout h5.subheader,.panel.callout h6.subheader{line-height:1.4}.panel.callout a:not(.button){color:#008CBA}.panel.callout a:not(.button):hover,.panel.callout a:not(.button):focus{color:#0078a0}.panel.radius{border-radius:3px}.pricing-table{border:solid 1px #DDDDDD;margin-left:0;margin-bottom:1.25rem}.pricing-table *{list-style:none;line-height:1}.pricing-table .title{background-color:#333333;color:#EEEEEE;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size:1rem;font-weight:normal;padding:0.9375rem 1.25rem;text-align:center}.pricing-table .price{background-color:#F6F6F6;color:#333333;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size:2rem;font-weight:normal;padding:0.9375rem 1.25rem;text-align:center}.pricing-table .description{background-color:#FFFFFF;border-bottom:dotted 1px #DDDDDD;color:#777777;font-size:0.75rem;font-weight:normal;line-height:1.4;padding:0.9375rem;text-align:center}.pricing-table .bullet-item{background-color:#FFFFFF;border-bottom:dotted 1px #DDDDDD;color:#333333;font-size:0.875rem;font-weight:normal;padding:0.9375rem;text-align:center}.pricing-table .cta-button{background-color:#FFFFFF;padding:1.25rem 1.25rem 0;text-align:center}.progress{background-color:#F6F6F6;border:1px solid white;height:1.5625rem;margin-bottom:0.625rem;padding:0.125rem}.progress .meter{background:#008CBA;display:block;height:100%}.progress.secondary .meter{background:#e7e7e7;display:block;height:100%}.progress.success .meter{background:#43AC6A;display:block;height:100%}.progress.alert .meter{background:#f04124;display:block;height:100%}.progress.radius{border-radius:3px}.progress.radius .meter{border-radius:2px}.progress.round{border-radius:1000px}.progress.round .meter{border-radius:999px}.range-slider{border:1px solid #DDDDDD;margin:1.25rem 0;position:relative;-ms-touch-action:none;touch-action:none;display:block;height:1rem;width:100%;background:#FAFAFA}.range-slider.vertical-range{border:1px solid #DDDDDD;margin:1.25rem 0;position:relative;-ms-touch-action:none;touch-action:none;display:inline-block;height:12.5rem;width:1rem}.range-slider.vertical-range .range-slider-handle{bottom:-10.5rem;margin-left:-0.5rem;margin-top:0;position:absolute}.range-slider.vertical-range .range-slider-active-segment{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;border-top-left-radius:initial;bottom:0;height:auto;width:0.875rem}.range-slider.radius{background:#FAFAFA;border-radius:3px}.range-slider.radius .range-slider-handle{background:#008CBA;border-radius:3px}.range-slider.radius .range-slider-handle:hover{background:#007ba4}.range-slider.round{background:#FAFAFA;border-radius:1000px}.range-slider.round .range-slider-handle{background:#008CBA;border-radius:1000px}.range-slider.round .range-slider-handle:hover{background:#007ba4}.range-slider.disabled,.range-slider[disabled]{background:#FAFAFA;cursor:not-allowed;opacity:0.7}.range-slider.disabled .range-slider-handle,.range-slider[disabled] .range-slider-handle{background:#008CBA;cursor:default;opacity:0.7}.range-slider.disabled .range-slider-handle:hover,.range-slider[disabled] .range-slider-handle:hover{background:#007ba4}.range-slider-active-segment{background:#e5e5e5;border-bottom-left-radius:inherit;border-top-left-radius:inherit;display:inline-block;height:0.875rem;position:absolute}.range-slider-handle{border:1px solid none;cursor:pointer;display:inline-block;height:1.375rem;position:absolute;top:-0.3125rem;width:2rem;z-index:1;-ms-touch-action:manipulation;touch-action:manipulation;background:#008CBA}.range-slider-handle:hover{background:#007ba4}.reveal-modal-bg{background:#000000;background:rgba(0,0,0,0.45);bottom:0;display:none;left:0;position:fixed;right:0;top:0;z-index:1004;left:0}.reveal-modal{border-radius:3px;display:none;position:absolute;top:0;visibility:hidden;width:100%;z-index:1005;left:0;background-color:#FFFFFF;padding:1.875rem;border:solid 1px #666666;box-shadow:0 0 10px rgba(0,0,0,0.4)}@media only screen and (max-width: 40em){.reveal-modal{min-height:100vh}}.reveal-modal .column,.reveal-modal .columns{min-width:0}.reveal-modal>:first-child{margin-top:0}.reveal-modal>:last-child{margin-bottom:0}@media only screen and (min-width: 40.0625em){.reveal-modal{left:0;margin:0 auto;max-width:62.5rem;right:0;width:80%}}@media only screen and (min-width: 40.0625em){.reveal-modal{top:6.25rem}}.reveal-modal.radius{border-radius:3px}.reveal-modal.round{border-radius:1000px}.reveal-modal.collapse{padding:0}@media only screen and (min-width: 40.0625em){.reveal-modal.tiny{left:0;margin:0 auto;max-width:62.5rem;right:0;width:30%}}@media only screen and (min-width: 40.0625em){.reveal-modal.small{left:0;margin:0 auto;max-width:62.5rem;right:0;width:40%}}@media only screen and (min-width: 40.0625em){.reveal-modal.medium{left:0;margin:0 auto;max-width:62.5rem;right:0;width:60%}}@media only screen and (min-width: 40.0625em){.reveal-modal.large{left:0;margin:0 auto;max-width:62.5rem;right:0;width:70%}}@media only screen and (min-width: 40.0625em){.reveal-modal.xlarge{left:0;margin:0 auto;max-width:62.5rem;right:0;width:95%}}.reveal-modal.full{height:100vh;height:100%;left:0;margin-left:0 !important;max-width:none !important;min-height:100vh;top:0}@media only screen and (min-width: 40.0625em){.reveal-modal.full{left:0;margin:0 auto;max-width:62.5rem;right:0;width:100%}}.reveal-modal.toback{z-index:1003}.reveal-modal .close-reveal-modal{color:#AAAAAA;cursor:pointer;font-size:2.5rem;font-weight:bold;line-height:1;position:absolute;top:0.625rem;right:1.375rem}.side-nav{display:block;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;list-style-position:outside;list-style-type:none;margin:0;padding:0.4375rem 0}.side-nav li{font-size:0.875rem;font-weight:normal;margin:0 0 0 0}.side-nav li a:not(.button){color:#008CBA;display:block;margin:0;padding:0.4375rem 0.875rem}.side-nav li a:not(.button):hover,.side-nav li a:not(.button):focus{background:rgba(0,0,0,0.025);color:#1cc7ff}.side-nav li a:not(.button):active{color:#1cc7ff}.side-nav li.active>a:first-child:not(.button){color:#1cc7ff;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-weight:normal}.side-nav li.divider{border-top:1px solid;height:0;list-style:none;padding:0;border-top-color:white}.side-nav li.heading{color:#008CBA;font-size:0.875rem;font-weight:bold;text-transform:uppercase}.split.button{position:relative;padding-right:5.0625rem}.split.button span{display:block;height:100%;position:absolute;right:0;top:0;border-left:solid 1px}.split.button span:after{position:absolute;content:"";width:0;height:0;display:block;border-style:inset;top:50%;left:50%}.split.button span:active{background-color:rgba(0,0,0,0.1)}.split.button span{border-left-color:rgba(255,255,255,0.5)}.split.button span{width:3.09375rem}.split.button span:after{border-top-style:solid;border-width:0.375rem;margin-left:-0.375rem;top:48%}.split.button span:after{border-color:#FFFFFF transparent transparent transparent}.split.button.secondary span{border-left-color:rgba(255,255,255,0.5)}.split.button.secondary span:after{border-color:#FFFFFF transparent transparent transparent}.split.button.alert span{border-left-color:rgba(255,255,255,0.5)}.split.button.success span{border-left-color:rgba(255,255,255,0.5)}.split.button.tiny{padding-right:3.75rem}.split.button.tiny span{width:2.25rem}.split.button.tiny span:after{border-top-style:solid;border-width:0.375rem;margin-left:-0.375rem;top:48%}.split.button.small{padding-right:4.375rem}.split.button.small span{width:2.625rem}.split.button.small span:after{border-top-style:solid;border-width:0.4375rem;margin-left:-0.375rem;top:48%}.split.button.large{padding-right:5.5rem}.split.button.large span{width:3.4375rem}.split.button.large span:after{border-top-style:solid;border-width:0.3125rem;margin-left:-0.375rem;top:48%}.split.button.expand{padding-left:2rem}.split.button.secondary span:after{border-color:#333333 transparent transparent transparent}.split.button.radius span{-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}.split.button.round span{-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}.split.button.no-pip span:before{border-style:none}.split.button.no-pip span:after{border-style:none}.split.button.no-pip span>i{display:block;left:50%;margin-left:-0.28889em;margin-top:-0.48889em;position:absolute;top:50%}.sub-nav{display:block;margin:-0.25rem 0 1.125rem;overflow:hidden;padding-top:0.25rem;width:auto}.sub-nav dt{text-transform:uppercase}.sub-nav dt,.sub-nav dd,.sub-nav li{color:#999999;float:left;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size:0.875rem;font-weight:normal;margin-left:1rem;margin-bottom:0}.sub-nav dt a,.sub-nav dd a,.sub-nav li a{color:#999999;padding:0.1875rem 1rem;text-decoration:none}.sub-nav dt a:hover,.sub-nav dd a:hover,.sub-nav li a:hover{color:#737373}.sub-nav dt.active a,.sub-nav dd.active a,.sub-nav li.active a{border-radius:3px;background:#008CBA;color:#FFFFFF;cursor:default;font-weight:normal;padding:0.1875rem 1rem}.sub-nav dt.active a:hover,.sub-nav dd.active a:hover,.sub-nav li.active a:hover{background:#0078a0}.switch{border:none;margin-bottom:1.5rem;outline:0;padding:0;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.switch label{background:#DDDDDD;color:transparent;cursor:pointer;display:block;margin-bottom:1rem;position:relative;text-indent:100%;width:4rem;height:2rem;transition:left 0.15s ease-out}.switch input{left:10px;opacity:0;padding:0;position:absolute;top:9px}.switch input+label{margin-left:0;margin-right:0}.switch label:after{background:#FFFFFF;content:"";display:block;height:1.5rem;left:.25rem;position:absolute;top:.25rem;width:1.5rem;-webkit-transition:left 0.15s ease-out;-moz-transition:left 0.15s ease-out;-o-transition:translate3d(0, 0, 0);transition:left 0.15s ease-out;-webkit-transform:translate3d(0, 0, 0);-moz-transform:translate3d(0, 0, 0);-ms-transform:translate3d(0, 0, 0);-o-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}.switch input:checked+label{background:#008CBA}.switch input:checked+label:after{left:2.25rem}.switch label{height:2rem;width:4rem}.switch label:after{height:1.5rem;width:1.5rem}.switch input:checked+label:after{left:2.25rem}.switch label{color:transparent;background:#DDDDDD}.switch label:after{background:#FFFFFF}.switch input:checked+label{background:#008CBA}.switch.large label{height:2.5rem;width:5rem}.switch.large label:after{height:2rem;width:2rem}.switch.large input:checked+label:after{left:2.75rem}.switch.small label{height:1.75rem;width:3.5rem}.switch.small label:after{height:1.25rem;width:1.25rem}.switch.small input:checked+label:after{left:2rem}.switch.tiny label{height:1.5rem;width:3rem}.switch.tiny label:after{height:1rem;width:1rem}.switch.tiny input:checked+label:after{left:1.75rem}.switch.radius label{border-radius:4px}.switch.radius label:after{border-radius:3px}.switch.round{border-radius:1000px}.switch.round label{border-radius:2rem}.switch.round label:after{border-radius:2rem}table{background:#FFFFFF;border:solid 1px #DDDDDD;margin-bottom:1.25rem;table-layout:auto}table caption{background:transparent;color:#222222;font-size:1rem;font-weight:bold}table thead{background:#F5F5F5}table thead tr th,table thead tr td{color:#222222;font-size:0.875rem;font-weight:bold;padding:0.5rem 0.625rem 0.625rem}table tfoot{background:#F5F5F5}table tfoot tr th,table tfoot tr td{color:#222222;font-size:0.875rem;font-weight:bold;padding:0.5rem 0.625rem 0.625rem}table tr th,table tr td{color:#222222;font-size:0.875rem;padding:0.5625rem 0.625rem;text-align:left}table tr.even,table tr.alt,table tr:nth-of-type(even){background:#F9F9F9}table thead tr th,table tfoot tr th,table tfoot tr td,table tbody tr th,table tbody tr td,table tr td{display:table-cell;line-height:1.125rem}.tabs{margin-bottom:0 !important;margin-left:0}.tabs:before,.tabs:after{content:" ";display:table}.tabs:after{clear:both}.tabs dd,.tabs .tab-title{float:left;list-style:none;margin-bottom:0 !important;position:relative}.tabs dd>a,.tabs .tab-title>a{display:block;background-color:#EFEFEF;color:#222222;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size:1rem;padding:1rem 2rem}.tabs dd>a:hover,.tabs .tab-title>a:hover{background-color:#e1e1e1}.tabs dd.active a,.tabs .tab-title.active a{background-color:#FFFFFF;color:#222222}.tabs.radius dd:first-child a,.tabs.radius .tab:first-child a{-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}.tabs.radius dd:last-child a,.tabs.radius .tab:last-child a{-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}.tabs.vertical dd,.tabs.vertical .tab-title{position:inherit;float:none;display:block;top:auto}.tabs-content{margin-bottom:1.5rem;width:100%}.tabs-content:before,.tabs-content:after{content:" ";display:table}.tabs-content:after{clear:both}.tabs-content>.content{display:none;float:left;padding:0.9375rem 0;width:100%}.tabs-content>.content.active{display:block;float:none}.tabs-content>.content.contained{padding:0.9375rem}.tabs-content.vertical{display:block}.tabs-content.vertical>.content{padding:0 0.9375rem}@media only screen and (min-width: 40.0625em){.tabs.vertical{float:left;margin:0;margin-bottom:1.25rem !important;max-width:20%;width:20%}.tabs-content.vertical{float:left;margin-left:-1px;max-width:80%;padding-left:1rem;width:80%}}.no-js .tabs-content>.content{display:block;float:none}.th{border:solid 4px #FFFFFF;box-shadow:0 0 0 1px rgba(0,0,0,0.2);display:inline-block;line-height:0;max-width:100%;transition:all 200ms ease-out}.th:hover,.th:focus{box-shadow:0 0 6px 1px rgba(0,140,186,0.5)}.th.radius{border-radius:3px}.has-tip{border-bottom:dotted 1px #CCCCCC;color:#333333;cursor:help;font-weight:bold}.has-tip:hover,.has-tip:focus{border-bottom:dotted 1px #003f54;color:#008CBA}.has-tip.tip-left,.has-tip.tip-right{float:none !important}.tooltip{background:#333333;color:#FFFFFF;display:none;font-size:0.875rem;font-weight:normal;line-height:1.3;max-width:300px;padding:0.75rem;position:absolute;width:100%;z-index:1006;left:50%}.tooltip>.nub{border-color:transparent transparent #333333 transparent;border:solid 5px;display:block;height:0;pointer-events:none;position:absolute;top:-10px;width:0;left:5px}.tooltip>.nub.rtl{left:auto;right:5px}.tooltip.radius{border-radius:3px}.tooltip.round{border-radius:1000px}.tooltip.round>.nub{left:2rem}.tooltip.opened{border-bottom:dotted 1px #003f54 !important;color:#008CBA !important}.tap-to-close{color:#777777;display:block;font-size:0.625rem;font-weight:normal}@media only screen and (min-width: 40.0625em){.tooltip>.nub{border-color:transparent transparent #333333 transparent;top:-10px}.tooltip.tip-top>.nub{border-color:#333333 transparent transparent transparent;bottom:-10px;top:auto}.tooltip.tip-left,.tooltip.tip-right{float:none !important}.tooltip.tip-left>.nub{border-color:transparent transparent transparent #333333;left:auto;margin-top:-5px;right:-10px;top:50%}.tooltip.tip-right>.nub{border-color:transparent #333333 transparent transparent;left:-10px;margin-top:-5px;right:auto;top:50%}}meta.foundation-mq-topbar{font-family:"/only screen and (min-width:40.0625em)/";width:40.0625em}.contain-to-grid{width:100%;background:#333333}.contain-to-grid .top-bar{margin-bottom:0}.fixed{position:fixed;top:0;width:100%;z-index:99;left:0}.fixed.expanded:not(.top-bar){height:auto;max-height:100%;overflow-y:auto;width:100%}.fixed.expanded:not(.top-bar) .title-area{position:fixed;width:100%;z-index:99}.fixed.expanded:not(.top-bar) .top-bar-section{margin-top:2.8125rem;z-index:98}.top-bar{background:#333333;height:2.8125rem;line-height:2.8125rem;margin-bottom:0;overflow:hidden;position:relative}.top-bar ul{list-style:none;margin-bottom:0}.top-bar .row{max-width:none}.top-bar form,.top-bar input,.top-bar select{margin-bottom:0}.top-bar input,.top-bar select{font-size:0.75rem;height:1.75rem;padding-bottom:.35rem;padding-top:.35rem}.top-bar .button,.top-bar button{font-size:0.75rem;margin-bottom:0;padding-bottom:0.4125rem;padding-top:0.4125rem}@media only screen and (max-width: 40em){.top-bar .button,.top-bar button{position:relative;top:-1px}}.top-bar .title-area{margin:0;position:relative}.top-bar .name{font-size:16px;height:2.8125rem;margin:0}.top-bar .name h1,.top-bar .name h2,.top-bar .name h3,.top-bar .name h4,.top-bar .name p,.top-bar .name span{font-size:1.0625rem;line-height:2.8125rem;margin:0}.top-bar .name h1 a,.top-bar .name h2 a,.top-bar .name h3 a,.top-bar .name h4 a,.top-bar .name p a,.top-bar .name span a{color:#FFFFFF;display:block;font-weight:normal;padding:0 0.9375rem;width:75%}.top-bar .toggle-topbar{position:absolute;right:0;top:0}.top-bar .toggle-topbar a{color:#FFFFFF;display:block;font-size:0.8125rem;font-weight:bold;height:2.8125rem;line-height:2.8125rem;padding:0 0.9375rem;position:relative;text-transform:uppercase}.top-bar .toggle-topbar.menu-icon{margin-top:-16px;top:50%}.top-bar .toggle-topbar.menu-icon a{color:#FFFFFF;height:34px;line-height:33px;padding:0 2.5rem 0 0.9375rem;position:relative}.top-bar .toggle-topbar.menu-icon a span::after{content:"";display:block;height:0;position:absolute;margin-top:-8px;top:50%;right:0.9375rem;box-shadow:0 0 0 1px #FFFFFF, 0 7px 0 1px #FFFFFF, 0 14px 0 1px #FFFFFF;width:16px}.top-bar .toggle-topbar.menu-icon a span:hover:after{box-shadow:0 0 0 1px "", 0 7px 0 1px "", 0 14px 0 1px ""}.top-bar.expanded{background:transparent;height:auto}.top-bar.expanded .title-area{background:#333333}.top-bar.expanded .toggle-topbar a{color:#888888}.top-bar.expanded .toggle-topbar a span::after{box-shadow:0 0 0 1px #888888, 0 7px 0 1px #888888, 0 14px 0 1px #888888}@media screen and (-webkit-min-device-pixel-ratio: 0){.top-bar.expanded .top-bar-section .has-dropdown.moved>.dropdown,.top-bar.expanded .top-bar-section .dropdown{clip:initial}.top-bar.expanded .top-bar-section .has-dropdown:not(.moved)>ul{padding:0}}.top-bar-section{left:0;position:relative;width:auto;transition:left 300ms ease-out}.top-bar-section ul{display:block;font-size:16px;height:auto;margin:0;padding:0;width:100%}.top-bar-section .divider,.top-bar-section [role="separator"]{border-top:solid 1px #1a1a1a;clear:both;height:1px;width:100%}.top-bar-section ul li{background:#333333}.top-bar-section ul li>a{color:#FFFFFF;display:block;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-size:0.8125rem;font-weight:normal;padding-left:0.9375rem;padding:12px 0 12px 0.9375rem;text-transform:none;width:100%}.top-bar-section ul li>a.button{font-size:0.8125rem;padding-left:0.9375rem;padding-right:0.9375rem;background-color:#008CBA;border-color:#007095;color:#FFFFFF}.top-bar-section ul li>a.button:hover,.top-bar-section ul li>a.button:focus{background-color:#007095}.top-bar-section ul li>a.button:hover,.top-bar-section ul li>a.button:focus{color:#FFFFFF}.top-bar-section ul li>a.button.secondary{background-color:#e7e7e7;border-color:#b9b9b9;color:#333333}.top-bar-section ul li>a.button.secondary:hover,.top-bar-section ul li>a.button.secondary:focus{background-color:#b9b9b9}.top-bar-section ul li>a.button.secondary:hover,.top-bar-section ul li>a.button.secondary:focus{color:#333333}.top-bar-section ul li>a.button.success{background-color:#43AC6A;border-color:#368a55;color:#FFFFFF}.top-bar-section ul li>a.button.success:hover,.top-bar-section ul li>a.button.success:focus{background-color:#368a55}.top-bar-section ul li>a.button.success:hover,.top-bar-section ul li>a.button.success:focus{color:#FFFFFF}.top-bar-section ul li>a.button.alert{background-color:#f04124;border-color:#cf2a0e;color:#FFFFFF}.top-bar-section ul li>a.button.alert:hover,.top-bar-section ul li>a.button.alert:focus{background-color:#cf2a0e}.top-bar-section ul li>a.button.alert:hover,.top-bar-section ul li>a.button.alert:focus{color:#FFFFFF}.top-bar-section ul li>a.button.warning{background-color:#f08a24;border-color:#cf6e0e;color:#FFFFFF}.top-bar-section ul li>a.button.warning:hover,.top-bar-section ul li>a.button.warning:focus{background-color:#cf6e0e}.top-bar-section ul li>a.button.warning:hover,.top-bar-section ul li>a.button.warning:focus{color:#FFFFFF}.top-bar-section ul li>a.button.info{background-color:#a0d3e8;border-color:#61b6d9;color:#333333}.top-bar-section ul li>a.button.info:hover,.top-bar-section ul li>a.button.info:focus{background-color:#61b6d9}.top-bar-section ul li>a.button.info:hover,.top-bar-section ul li>a.button.info:focus{color:#FFFFFF}.top-bar-section ul li>button{font-size:0.8125rem;padding-left:0.9375rem;padding-right:0.9375rem;background-color:#008CBA;border-color:#007095;color:#FFFFFF}.top-bar-section ul li>button:hover,.top-bar-section ul li>button:focus{background-color:#007095}.top-bar-section ul li>button:hover,.top-bar-section ul li>button:focus{color:#FFFFFF}.top-bar-section ul li>button.secondary{background-color:#e7e7e7;border-color:#b9b9b9;color:#333333}.top-bar-section ul li>button.secondary:hover,.top-bar-section ul li>button.secondary:focus{background-color:#b9b9b9}.top-bar-section ul li>button.secondary:hover,.top-bar-section ul li>button.secondary:focus{color:#333333}.top-bar-section ul li>button.success{background-color:#43AC6A;border-color:#368a55;color:#FFFFFF}.top-bar-section ul li>button.success:hover,.top-bar-section ul li>button.success:focus{background-color:#368a55}.top-bar-section ul li>button.success:hover,.top-bar-section ul li>button.success:focus{color:#FFFFFF}.top-bar-section ul li>button.alert{background-color:#f04124;border-color:#cf2a0e;color:#FFFFFF}.top-bar-section ul li>button.alert:hover,.top-bar-section ul li>button.alert:focus{background-color:#cf2a0e}.top-bar-section ul li>button.alert:hover,.top-bar-section ul li>button.alert:focus{color:#FFFFFF}.top-bar-section ul li>button.warning{background-color:#f08a24;border-color:#cf6e0e;color:#FFFFFF}.top-bar-section ul li>button.warning:hover,.top-bar-section ul li>button.warning:focus{background-color:#cf6e0e}.top-bar-section ul li>button.warning:hover,.top-bar-section ul li>button.warning:focus{color:#FFFFFF}.top-bar-section ul li>button.info{background-color:#a0d3e8;border-color:#61b6d9;color:#333333}.top-bar-section ul li>button.info:hover,.top-bar-section ul li>button.info:focus{background-color:#61b6d9}.top-bar-section ul li>button.info:hover,.top-bar-section ul li>button.info:focus{color:#FFFFFF}.top-bar-section ul li:hover:not(.has-form)>a{background-color:#555555;color:#FFFFFF;background:#222222}.top-bar-section ul li.active>a{background:#008CBA;color:#FFFFFF}.top-bar-section ul li.active>a:hover{background:#0078a0;color:#FFFFFF}.top-bar-section .has-form{padding:0.9375rem}.top-bar-section .has-dropdown{position:relative}.top-bar-section .has-dropdown>a:after{border:inset 5px;content:"";display:block;height:0;width:0;border-color:transparent transparent transparent rgba(255,255,255,0.4);border-left-style:solid;margin-right:0.9375rem;margin-top:-4.5px;position:absolute;top:50%;right:0}.top-bar-section .has-dropdown.moved{position:static}.top-bar-section .has-dropdown.moved>.dropdown{position:static !important;height:auto;width:auto;overflow:visible;clip:auto;display:block;position:absolute !important;width:100%}.top-bar-section .has-dropdown.moved>a:after{display:none}.top-bar-section .dropdown{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px;display:block;padding:0;position:absolute;top:0;z-index:99;left:100%}.top-bar-section .dropdown li{height:auto;width:100%}.top-bar-section .dropdown li a{font-weight:normal;padding:8px 0.9375rem}.top-bar-section .dropdown li a.parent-link{font-weight:normal}.top-bar-section .dropdown li.title h5,.top-bar-section .dropdown li.parent-link{margin-bottom:0;margin-top:0;font-size:1.125rem}.top-bar-section .dropdown li.title h5 a,.top-bar-section .dropdown li.parent-link a{color:#FFFFFF;display:block}.top-bar-section .dropdown li.title h5 a:hover,.top-bar-section .dropdown li.parent-link a:hover{background:none}.top-bar-section .dropdown li.has-form{padding:8px 0.9375rem}.top-bar-section .dropdown li .button,.top-bar-section .dropdown li button{top:auto}.top-bar-section .dropdown label{color:#777777;font-size:0.625rem;font-weight:bold;margin-bottom:0;padding:8px 0.9375rem 2px;text-transform:uppercase}.js-generated{display:block}@media only screen and (min-width: 40.0625em){.top-bar{background:#333333;overflow:visible}.top-bar:before,.top-bar:after{content:" ";display:table}.top-bar:after{clear:both}.top-bar .toggle-topbar{display:none}.top-bar .title-area{float:left}.top-bar .name h1 a,.top-bar .name h2 a,.top-bar .name h3 a,.top-bar .name h4 a,.top-bar .name h5 a,.top-bar .name h6 a{width:auto}.top-bar input,.top-bar select,.top-bar .button,.top-bar button{font-size:0.875rem;height:1.75rem;position:relative;top:0.53125rem}.top-bar.expanded{background:#333333}.contain-to-grid .top-bar{margin-bottom:0;margin:0 auto;max-width:62.5rem}.top-bar-section{transition:none 0 0;left:0 !important}.top-bar-section ul{display:inline;height:auto !important;width:auto}.top-bar-section ul li{float:left}.top-bar-section ul li .js-generated{display:none}.top-bar-section li.hover>a:not(.button){background-color:#555555;background:#222222;color:#FFFFFF}.top-bar-section li:not(.has-form) a:not(.button){background:#333333;line-height:2.8125rem;padding:0 0.9375rem}.top-bar-section li:not(.has-form) a:not(.button):hover{background-color:#555555;background:#222222}.top-bar-section li.active:not(.has-form) a:not(.button){background:#008CBA;color:#FFFFFF;line-height:2.8125rem;padding:0 0.9375rem}.top-bar-section li.active:not(.has-form) a:not(.button):hover{background:#0078a0;color:#FFFFFF}.top-bar-section .has-dropdown>a{padding-right:2.1875rem !important}.top-bar-section .has-dropdown>a:after{border:inset 5px;content:"";display:block;height:0;width:0;border-color:rgba(255,255,255,0.4) transparent transparent transparent;border-top-style:solid;margin-top:-2.5px;top:1.40625rem}.top-bar-section .has-dropdown.moved{position:relative}.top-bar-section .has-dropdown.moved>.dropdown{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px;display:block}.top-bar-section .has-dropdown.hover>.dropdown,.top-bar-section .has-dropdown.not-click:hover>.dropdown{position:static !important;height:auto;width:auto;overflow:visible;clip:auto;display:block;position:absolute !important}.top-bar-section .has-dropdown>a:focus+.dropdown{position:static !important;height:auto;width:auto;overflow:visible;clip:auto;display:block;position:absolute !important}.top-bar-section .has-dropdown .dropdown li.has-dropdown>a:after{border:none;content:"\00bb";top:0.1875rem;right:5px}.top-bar-section .dropdown{left:0;background:transparent;min-width:100%;top:auto}.top-bar-section .dropdown li a{background:#333333;color:#FFFFFF;line-height:2.8125rem;padding:12px 0.9375rem;white-space:nowrap}.top-bar-section .dropdown li:not(.has-form):not(.active)>a:not(.button){background:#333333;color:#FFFFFF}.top-bar-section .dropdown li:not(.has-form):not(.active):hover>a:not(.button){background-color:#555555;color:#FFFFFF;background:#222222}.top-bar-section .dropdown li label{background:#333333;white-space:nowrap}.top-bar-section .dropdown li .dropdown{left:100%;top:0}.top-bar-section>ul>.divider,.top-bar-section>ul>[role="separator"]{border-right:solid 1px #4e4e4e;border-bottom:none;border-top:none;clear:none;height:2.8125rem;width:0}.top-bar-section .has-form{background:#333333;height:2.8125rem;padding:0 0.9375rem}.top-bar-section .right li .dropdown{left:auto;right:0}.top-bar-section .right li .dropdown li .dropdown{right:100%}.top-bar-section .left li .dropdown{right:auto;left:0}.top-bar-section .left li .dropdown li .dropdown{left:100%}.no-js .top-bar-section ul li:hover>a{background-color:#555555;background:#222222;color:#FFFFFF}.no-js .top-bar-section ul li:active>a{background:#008CBA;color:#FFFFFF}.no-js .top-bar-section .has-dropdown:hover>.dropdown{position:static !important;height:auto;width:auto;overflow:visible;clip:auto;display:block;position:absolute !important}.no-js .top-bar-section .has-dropdown>a:focus+.dropdown{position:static !important;height:auto;width:auto;overflow:visible;clip:auto;display:block;position:absolute !important}}.text-left{text-align:left !important}.text-right{text-align:right !important}.text-center{text-align:center !important}.text-justify{text-align:justify !important}@media only screen and (max-width: 40em){.small-only-text-left{text-align:left !important}.small-only-text-right{text-align:right !important}.small-only-text-center{text-align:center !important}.small-only-text-justify{text-align:justify !important}}@media only screen{.small-text-left{text-align:left !important}.small-text-right{text-align:right !important}.small-text-center{text-align:center !important}.small-text-justify{text-align:justify !important}}@media only screen and (min-width: 40.0625em) and (max-width: 64em){.medium-only-text-left{text-align:left !important}.medium-only-text-right{text-align:right !important}.medium-only-text-center{text-align:center !important}.medium-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 40.0625em){.medium-text-left{text-align:left !important}.medium-text-right{text-align:right !important}.medium-text-center{text-align:center !important}.medium-text-justify{text-align:justify !important}}@media only screen and (min-width: 64.0625em) and (max-width: 90em){.large-only-text-left{text-align:left !important}.large-only-text-right{text-align:right !important}.large-only-text-center{text-align:center !important}.large-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 64.0625em){.large-text-left{text-align:left !important}.large-text-right{text-align:right !important}.large-text-center{text-align:center !important}.large-text-justify{text-align:justify !important}}@media only screen and (min-width: 90.0625em) and (max-width: 120em){.xlarge-only-text-left{text-align:left !important}.xlarge-only-text-right{text-align:right !important}.xlarge-only-text-center{text-align:center !important}.xlarge-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 90.0625em){.xlarge-text-left{text-align:left !important}.xlarge-text-right{text-align:right !important}.xlarge-text-center{text-align:center !important}.xlarge-text-justify{text-align:justify !important}}@media only screen and (min-width: 120.0625em) and (max-width: 6249999.9375em){.xxlarge-only-text-left{text-align:left !important}.xxlarge-only-text-right{text-align:right !important}.xxlarge-only-text-center{text-align:center !important}.xxlarge-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 120.0625em){.xxlarge-text-left{text-align:left !important}.xxlarge-text-right{text-align:right !important}.xxlarge-text-center{text-align:center !important}.xxlarge-text-justify{text-align:justify !important}}div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}a{color:#008CBA;line-height:inherit;text-decoration:none}a:hover,a:focus{color:#0078a0}a img{border:none}p{font-family:inherit;font-size:1rem;font-weight:normal;line-height:1.6;margin-bottom:0.1875rem;text-rendering:optimizeLegibility}p.lead{font-size:1.21875rem;line-height:1.6}p aside{font-size:0.875rem;font-style:italic;line-height:1.35}h1,h2,h3,h4,h5,h6{color:#222222;font-family:"Source Sans Pro", "Nunito", "Helvetica Neue", Helvetica, Arial, sans-serif;font-style:normal;font-weight:normal;line-height:1.4;margin-bottom:0.5rem;margin-top:1rem;text-rendering:optimizeLegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{color:#6f6f6f;font-size:60%;line-height:0}h1{font-size:1.175rem}h2{font-size:0.875rem}h3{font-size:0.9875rem}h4{font-size:0.8875rem}h5{font-size:1rem}h6{font-size:1rem}.subheader{line-height:1.4;color:#6f6f6f;font-weight:normal;margin-top:1rem;margin-bottom:0.5rem}hr{border:solid #DDDDDD;border-width:1px 0 0;clear:both;height:0;margin:1.25rem 0 1.1875rem}em,i{font-style:italic;line-height:inherit}strong,b{font-weight:bold;line-height:inherit}small{font-size:60%;line-height:inherit}code{background-color:#f8f8f8;border-color:#dfdfdf;border-style:none;border-width:1px;color:#333333;font-family:Consolas, "Liberation Mono", Courier, monospace;font-weight:normal;padding:0rem}ul,ol,dl{font-family:inherit;font-size:1rem;line-height:1.6;list-style-position:outside;margin-bottom:0.1875rem}ul{margin-left:1.1rem}ul.no-bullet{margin-left:0}ul.no-bullet li ul,ul.no-bullet li ol{margin-left:1.25rem;margin-bottom:0;list-style:none}ul li ul,ul li ol{margin-left:1.25rem;margin-bottom:0}ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}ul.square{list-style-type:square;margin-left:1.1rem}ul.circle{list-style-type:circle;margin-left:1.1rem}ul.disc{list-style-type:disc;margin-left:1.1rem}ul.no-bullet{list-style:none}ol{margin-left:1.4rem}ol li ul,ol li ol{margin-left:1.25rem;margin-bottom:0}dl dt{margin-bottom:0.3rem;font-weight:bold}dl dd{margin-bottom:0.75rem}abbr,acronym{text-transform:uppercase;font-size:90%;color:#222222;cursor:help}abbr{text-transform:none}abbr[title]{border-bottom:1px dotted #DDDDDD}blockquote{margin:0 0 0.1875rem;padding:0.5625rem 1.25rem 0 1.1875rem;border-left:1px solid #DDDDDD}blockquote cite{display:block;font-size:0.8125rem;color:#555555}blockquote cite:before{content:"\2014 \0020"}blockquote cite a,blockquote cite a:visited{color:#555555}blockquote,blockquote p{line-height:1.6;color:#6f6f6f}.vcard{display:inline-block;margin:0 0 1.25rem 0;border:1px solid #DDDDDD;padding:0.625rem 0.75rem}.vcard li{margin:0;display:block}.vcard .fn{font-weight:bold;font-size:0.9375rem}.vevent .summary{font-weight:bold}.vevent abbr{cursor:default;text-decoration:none;font-weight:bold;border:none;padding:0 0.0625rem}@media only screen and (min-width: 40.0625em){h1,h2,h3,h4,h5,h6{line-height:1.4}h1{font-size:1.8rem}h2{font-size:1.5rem}h3{font-size:1.3rem}h4{font-size:1.2rem}h5{font-size:1rem}h6{font-size:1rem}}.off-canvas-wrap{-webkit-backface-visibility:hidden;position:relative;width:100%;overflow:hidden}.off-canvas-wrap.move-right,.off-canvas-wrap.move-left{min-height:100%;-webkit-overflow-scrolling:touch}.inner-wrap{position:relative;width:100%;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.inner-wrap:before,.inner-wrap:after{content:" ";display:table}.inner-wrap:after{clear:both}.tab-bar{-webkit-backface-visibility:hidden;background:#333333;color:#FFFFFF;height:2.8125rem;line-height:2.8125rem;position:relative}.tab-bar h1,.tab-bar h2,.tab-bar h3,.tab-bar h4,.tab-bar h5,.tab-bar h6{color:#FFFFFF;font-weight:bold;line-height:2.8125rem;margin:0}.tab-bar h1,.tab-bar h2,.tab-bar h3,.tab-bar h4{font-size:1rem}.left-small{height:2.8125rem;position:absolute;top:0;width:2.8125rem;border-right:solid 1px #1a1a1a;left:0}.right-small{height:2.8125rem;position:absolute;top:0;width:2.8125rem;border-left:solid 1px #1a1a1a;right:0}.tab-bar-section{height:2.8125rem;padding:0 0.625rem;position:absolute;text-align:center;top:0}.tab-bar-section.left{text-align:left}.tab-bar-section.right{text-align:right}.tab-bar-section.left{left:0;right:2.8125rem}.tab-bar-section.right{left:2.8125rem;right:0}.tab-bar-section.middle{left:2.8125rem;right:2.8125rem}.tab-bar .menu-icon{color:#FFFFFF;display:block;height:2.8125rem;padding:0;position:relative;text-indent:2.1875rem;transform:translate3d(0, 0, 0);width:2.8125rem}.tab-bar .menu-icon span::after{content:"";display:block;height:0;position:absolute;top:50%;margin-top:-0.5rem;left:0.90625rem;box-shadow:0 0 0 1px #FFFFFF, 0 7px 0 1px #FFFFFF, 0 14px 0 1px #FFFFFF;width:1rem}.tab-bar .menu-icon span:hover:after{box-shadow:0 0 0 1px #b3b3b3, 0 7px 0 1px #b3b3b3, 0 14px 0 1px #b3b3b3}.left-off-canvas-menu{-webkit-backface-visibility:hidden;background:#333333;bottom:0;box-sizing:content-box;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;overflow-x:hidden;overflow-y:auto;position:absolute;top:0;transition:transform 500ms ease 0s;width:15.625rem;z-index:1001;-webkit-transform:translate3d(-100%, 0, 0);-moz-transform:translate3d(-100%, 0, 0);-ms-transform:translate(-100%, 0);-ms-transform:translate3d(-100%, 0, 0);-o-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0}.left-off-canvas-menu *{-webkit-backface-visibility:hidden}.right-off-canvas-menu{-webkit-backface-visibility:hidden;background:#333333;bottom:0;box-sizing:content-box;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;overflow-x:hidden;overflow-y:auto;position:absolute;top:0;transition:transform 500ms ease 0s;width:15.625rem;z-index:1001;-webkit-transform:translate3d(100%, 0, 0);-moz-transform:translate3d(100%, 0, 0);-ms-transform:translate(100%, 0);-ms-transform:translate3d(100%, 0, 0);-o-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);right:0}.right-off-canvas-menu *{-webkit-backface-visibility:hidden}ul.off-canvas-list{list-style-type:none;margin:0;padding:0}ul.off-canvas-list li label{background:#444444;border-bottom:none;border-top:1px solid #5e5e5e;color:#999999;display:block;font-size:0.75rem;font-weight:bold;margin:0;padding:0.3rem 0.9375rem;text-transform:uppercase}ul.off-canvas-list li a{border-bottom:1px solid #262626;color:rgba(255,255,255,0.7);display:block;padding:0.6666666667rem;transition:background 300ms ease}ul.off-canvas-list li a:hover{background:#242424}ul.off-canvas-list li a:active{background:#242424}.move-right>.inner-wrap{-webkit-transform:translate3d(15.625rem, 0, 0);-moz-transform:translate3d(15.625rem, 0, 0);-ms-transform:translate(15.625rem, 0);-ms-transform:translate3d(15.625rem, 0, 0);-o-transform:translate3d(15.625rem, 0, 0);transform:translate3d(15.625rem, 0, 0)}.move-right .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(0,0,0,0.5),4px 0 4px rgba(0,0,0,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.move-right .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}}.move-left>.inner-wrap{-webkit-transform:translate3d(-15.625rem, 0, 0);-moz-transform:translate3d(-15.625rem, 0, 0);-ms-transform:translate(-15.625rem, 0);-ms-transform:translate3d(-15.625rem, 0, 0);-o-transform:translate3d(-15.625rem, 0, 0);transform:translate3d(-15.625rem, 0, 0)}.move-left .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(0,0,0,0.5),4px 0 4px rgba(0,0,0,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.move-left .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}}.offcanvas-overlap .left-off-canvas-menu,.offcanvas-overlap .right-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(0,0,0,0.5),4px 0 4px rgba(0,0,0,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.offcanvas-overlap .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}}.offcanvas-overlap-left .right-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap-left .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(0,0,0,0.5),4px 0 4px rgba(0,0,0,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.offcanvas-overlap-left .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}}.offcanvas-overlap-right .left-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap-right .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(0,0,0,0.5),4px 0 4px rgba(0,0,0,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.offcanvas-overlap-right .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}}.no-csstransforms .left-off-canvas-menu{left:-15.625rem}.no-csstransforms .right-off-canvas-menu{right:-15.625rem}.no-csstransforms .move-left>.inner-wrap{right:15.625rem}.no-csstransforms .move-right>.inner-wrap{left:15.625rem}.left-submenu{-webkit-backface-visibility:hidden;-webkit-overflow-scrolling:touch;background:#333333;bottom:0;box-sizing:content-box;margin:0;overflow-x:hidden;overflow-y:auto;position:absolute;top:0;width:15.625rem;z-index:1002;-webkit-transform:translate3d(-100%, 0, 0);-moz-transform:translate3d(-100%, 0, 0);-ms-transform:translate(-100%, 0);-ms-transform:translate3d(-100%, 0, 0);-o-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.left-submenu *{-webkit-backface-visibility:hidden}.left-submenu .back>a{background:#444;border-bottom:none;border-top:1px solid #5e5e5e;color:#999999;font-weight:bold;padding:0.3rem 0.9375rem;text-transform:uppercase;margin:0}.left-submenu .back>a:hover{background:#303030;border-bottom:none;border-top:1px solid #5e5e5e}.left-submenu .back>a:before{content:"\AB";margin-right:.5rem;display:inline}.left-submenu.move-right,.left-submenu.offcanvas-overlap-right,.left-submenu.offcanvas-overlap{-webkit-transform:translate3d(0%, 0, 0);-moz-transform:translate3d(0%, 0, 0);-ms-transform:translate(0%, 0);-ms-transform:translate3d(0%, 0, 0);-o-transform:translate3d(0%, 0, 0);transform:translate3d(0%, 0, 0)}.right-submenu{-webkit-backface-visibility:hidden;-webkit-overflow-scrolling:touch;background:#333333;bottom:0;box-sizing:content-box;margin:0;overflow-x:hidden;overflow-y:auto;position:absolute;top:0;width:15.625rem;z-index:1002;-webkit-transform:translate3d(100%, 0, 0);-moz-transform:translate3d(100%, 0, 0);-ms-transform:translate(100%, 0);-ms-transform:translate3d(100%, 0, 0);-o-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);right:0;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.right-submenu *{-webkit-backface-visibility:hidden}.right-submenu .back>a{background:#444;border-bottom:none;border-top:1px solid #5e5e5e;color:#999999;font-weight:bold;padding:0.3rem 0.9375rem;text-transform:uppercase;margin:0}.right-submenu .back>a:hover{background:#303030;border-bottom:none;border-top:1px solid #5e5e5e}.right-submenu .back>a:after{content:"\BB";margin-left:.5rem;display:inline}.right-submenu.move-left,.right-submenu.offcanvas-overlap-left,.right-submenu.offcanvas-overlap{-webkit-transform:translate3d(0%, 0, 0);-moz-transform:translate3d(0%, 0, 0);-ms-transform:translate(0%, 0);-ms-transform:translate3d(0%, 0, 0);-o-transform:translate3d(0%, 0, 0);transform:translate3d(0%, 0, 0)}.left-off-canvas-menu ul.off-canvas-list li.has-submenu>a:after{content:"\BB";margin-left:.5rem;display:inline}.right-off-canvas-menu ul.off-canvas-list li.has-submenu>a:before{content:"\AB";margin-right:.5rem;display:inline}@media only screen{.show-for-small-only,.show-for-small-up,.show-for-small,.show-for-small-down,.hide-for-medium-only,.hide-for-medium-up,.hide-for-medium,.show-for-medium-down,.hide-for-large-only,.hide-for-large-up,.hide-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xlarge,.show-for-xlarge-down,.hide-for-xxlarge-only,.hide-for-xxlarge-up,.hide-for-xxlarge,.show-for-xxlarge-down{display:inherit !important}.hide-for-small-only,.hide-for-small-up,.hide-for-small,.hide-for-small-down,.show-for-medium-only,.show-for-medium-up,.show-for-medium,.hide-for-medium-down,.show-for-large-only,.show-for-large-up,.show-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.show-for-xlarge,.hide-for-xlarge-down,.show-for-xxlarge-only,.show-for-xxlarge-up,.show-for-xxlarge,.hide-for-xxlarge-down{display:none !important}.visible-for-small-only,.visible-for-small-up,.visible-for-small,.visible-for-small-down,.hidden-for-medium-only,.hidden-for-medium-up,.hidden-for-medium,.visible-for-medium-down,.hidden-for-large-only,.hidden-for-large-up,.hidden-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xlarge,.visible-for-xlarge-down,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up,.hidden-for-xxlarge,.visible-for-xxlarge-down{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.hidden-for-small-only,.hidden-for-small-up,.hidden-for-small,.hidden-for-small-down,.visible-for-medium-only,.visible-for-medium-up,.visible-for-medium,.hidden-for-medium-down,.visible-for-large-only,.visible-for-large-up,.visible-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xlarge,.hidden-for-xlarge-down,.visible-for-xxlarge-only,.visible-for-xxlarge-up,.visible-for-xxlarge,.hidden-for-xxlarge-down{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}table.show-for-small-only,table.show-for-small-up,table.show-for-small,table.show-for-small-down,table.hide-for-medium-only,table.hide-for-medium-up,table.hide-for-medium,table.show-for-medium-down,table.hide-for-large-only,table.hide-for-large-up,table.hide-for-large,table.show-for-large-down,table.hide-for-xlarge-only,table.hide-for-xlarge-up,table.hide-for-xlarge,table.show-for-xlarge-down,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up,table.hide-for-xxlarge,table.show-for-xxlarge-down{display:table !important}thead.show-for-small-only,thead.show-for-small-up,thead.show-for-small,thead.show-for-small-down,thead.hide-for-medium-only,thead.hide-for-medium-up,thead.hide-for-medium,thead.show-for-medium-down,thead.hide-for-large-only,thead.hide-for-large-up,thead.hide-for-large,thead.show-for-large-down,thead.hide-for-xlarge-only,thead.hide-for-xlarge-up,thead.hide-for-xlarge,thead.show-for-xlarge-down,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up,thead.hide-for-xxlarge,thead.show-for-xxlarge-down{display:table-header-group !important}tbody.show-for-small-only,tbody.show-for-small-up,tbody.show-for-small,tbody.show-for-small-down,tbody.hide-for-medium-only,tbody.hide-for-medium-up,tbody.hide-for-medium,tbody.show-for-medium-down,tbody.hide-for-large-only,tbody.hide-for-large-up,tbody.hide-for-large,tbody.show-for-large-down,tbody.hide-for-xlarge-only,tbody.hide-for-xlarge-up,tbody.hide-for-xlarge,tbody.show-for-xlarge-down,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up,tbody.hide-for-xxlarge,tbody.show-for-xxlarge-down{display:table-row-group !important}tr.show-for-small-only,tr.show-for-small-up,tr.show-for-small,tr.show-for-small-down,tr.hide-for-medium-only,tr.hide-for-medium-up,tr.hide-for-medium,tr.show-for-medium-down,tr.hide-for-large-only,tr.hide-for-large-up,tr.hide-for-large,tr.show-for-large-down,tr.hide-for-xlarge-only,tr.hide-for-xlarge-up,tr.hide-for-xlarge,tr.show-for-xlarge-down,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up,tr.hide-for-xxlarge,tr.show-for-xxlarge-down{display:table-row}th.show-for-small-only,td.show-for-small-only,th.show-for-small-up,td.show-for-small-up,th.show-for-small,td.show-for-small,th.show-for-small-down,td.show-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.hide-for-medium-up,td.hide-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.show-for-medium-down,td.show-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.hide-for-large-up,td.hide-for-large-up,th.hide-for-large,td.hide-for-large,th.show-for-large-down,td.show-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.hide-for-xlarge-up,td.hide-for-xlarge-up,th.hide-for-xlarge,td.hide-for-xlarge,th.show-for-xlarge-down,td.show-for-xlarge-down,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up,th.hide-for-xxlarge,td.hide-for-xxlarge,th.show-for-xxlarge-down,td.show-for-xxlarge-down{display:table-cell !important}}@media only screen and (min-width: 40.0625em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.show-for-medium-only,.show-for-medium-up,.show-for-medium,.show-for-medium-down,.hide-for-large-only,.hide-for-large-up,.hide-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xlarge,.show-for-xlarge-down,.hide-for-xxlarge-only,.hide-for-xxlarge-up,.hide-for-xxlarge,.show-for-xxlarge-down{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.hide-for-medium-only,.hide-for-medium-up,.hide-for-medium,.hide-for-medium-down,.show-for-large-only,.show-for-large-up,.show-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.show-for-xlarge,.hide-for-xlarge-down,.show-for-xxlarge-only,.show-for-xxlarge-up,.show-for-xxlarge,.hide-for-xxlarge-down{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.visible-for-medium-only,.visible-for-medium-up,.visible-for-medium,.visible-for-medium-down,.hidden-for-large-only,.hidden-for-large-up,.hidden-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xlarge,.visible-for-xlarge-down,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up,.hidden-for-xxlarge,.visible-for-xxlarge-down{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.hidden-for-medium-only,.hidden-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.visible-for-large-only,.visible-for-large-up,.visible-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xlarge,.hidden-for-xlarge-down,.visible-for-xxlarge-only,.visible-for-xxlarge-up,.visible-for-xxlarge,.hidden-for-xxlarge-down{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.show-for-medium-only,table.show-for-medium-up,table.show-for-medium,table.show-for-medium-down,table.hide-for-large-only,table.hide-for-large-up,table.hide-for-large,table.show-for-large-down,table.hide-for-xlarge-only,table.hide-for-xlarge-up,table.hide-for-xlarge,table.show-for-xlarge-down,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up,table.hide-for-xxlarge,table.show-for-xxlarge-down{display:table !important}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.show-for-medium-only,thead.show-for-medium-up,thead.show-for-medium,thead.show-for-medium-down,thead.hide-for-large-only,thead.hide-for-large-up,thead.hide-for-large,thead.show-for-large-down,thead.hide-for-xlarge-only,thead.hide-for-xlarge-up,thead.hide-for-xlarge,thead.show-for-xlarge-down,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up,thead.hide-for-xxlarge,thead.show-for-xxlarge-down{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.show-for-medium-only,tbody.show-for-medium-up,tbody.show-for-medium,tbody.show-for-medium-down,tbody.hide-for-large-only,tbody.hide-for-large-up,tbody.hide-for-large,tbody.show-for-large-down,tbody.hide-for-xlarge-only,tbody.hide-for-xlarge-up,tbody.hide-for-xlarge,tbody.show-for-xlarge-down,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up,tbody.hide-for-xxlarge,tbody.show-for-xxlarge-down{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.show-for-medium-only,tr.show-for-medium-up,tr.show-for-medium,tr.show-for-medium-down,tr.hide-for-large-only,tr.hide-for-large-up,tr.hide-for-large,tr.show-for-large-down,tr.hide-for-xlarge-only,tr.hide-for-xlarge-up,tr.hide-for-xlarge,tr.show-for-xlarge-down,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up,tr.hide-for-xxlarge,tr.show-for-xxlarge-down{display:table-row}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.show-for-medium-only,td.show-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.show-for-medium,td.show-for-medium,th.show-for-medium-down,td.show-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.hide-for-large-up,td.hide-for-large-up,th.hide-for-large,td.hide-for-large,th.show-for-large-down,td.show-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.hide-for-xlarge-up,td.hide-for-xlarge-up,th.hide-for-xlarge,td.hide-for-xlarge,th.show-for-xlarge-down,td.show-for-xlarge-down,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up,th.hide-for-xxlarge,td.hide-for-xxlarge,th.show-for-xxlarge-down,td.show-for-xxlarge-down{display:table-cell !important}}@media only screen and (min-width: 64.0625em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.hide-for-medium-only,.show-for-medium-up,.hide-for-medium,.hide-for-medium-down,.show-for-large-only,.show-for-large-up,.show-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xlarge,.show-for-xlarge-down,.hide-for-xxlarge-only,.hide-for-xxlarge-up,.hide-for-xxlarge,.show-for-xxlarge-down{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.show-for-medium-only,.hide-for-medium-up,.show-for-medium,.show-for-medium-down,.hide-for-large-only,.hide-for-large-up,.hide-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.show-for-xlarge,.hide-for-xlarge-down,.show-for-xxlarge-only,.show-for-xxlarge-up,.show-for-xxlarge,.hide-for-xxlarge-down{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.hidden-for-medium-only,.visible-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.visible-for-large-only,.visible-for-large-up,.visible-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xlarge,.visible-for-xlarge-down,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up,.hidden-for-xxlarge,.visible-for-xxlarge-down{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.visible-for-medium-only,.hidden-for-medium-up,.visible-for-medium,.visible-for-medium-down,.hidden-for-large-only,.hidden-for-large-up,.hidden-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xlarge,.hidden-for-xlarge-down,.visible-for-xxlarge-only,.visible-for-xxlarge-up,.visible-for-xxlarge,.hidden-for-xxlarge-down{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.hide-for-medium-only,table.show-for-medium-up,table.hide-for-medium,table.hide-for-medium-down,table.show-for-large-only,table.show-for-large-up,table.show-for-large,table.show-for-large-down,table.hide-for-xlarge-only,table.hide-for-xlarge-up,table.hide-for-xlarge,table.show-for-xlarge-down,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up,table.hide-for-xxlarge,table.show-for-xxlarge-down{display:table !important}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.hide-for-medium-only,thead.show-for-medium-up,thead.hide-for-medium,thead.hide-for-medium-down,thead.show-for-large-only,thead.show-for-large-up,thead.show-for-large,thead.show-for-large-down,thead.hide-for-xlarge-only,thead.hide-for-xlarge-up,thead.hide-for-xlarge,thead.show-for-xlarge-down,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up,thead.hide-for-xxlarge,thead.show-for-xxlarge-down{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.hide-for-medium-only,tbody.show-for-medium-up,tbody.hide-for-medium,tbody.hide-for-medium-down,tbody.show-for-large-only,tbody.show-for-large-up,tbody.show-for-large,tbody.show-for-large-down,tbody.hide-for-xlarge-only,tbody.hide-for-xlarge-up,tbody.hide-for-xlarge,tbody.show-for-xlarge-down,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up,tbody.hide-for-xxlarge,tbody.show-for-xxlarge-down{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.hide-for-medium-only,tr.show-for-medium-up,tr.hide-for-medium,tr.hide-for-medium-down,tr.show-for-large-only,tr.show-for-large-up,tr.show-for-large,tr.show-for-large-down,tr.hide-for-xlarge-only,tr.hide-for-xlarge-up,tr.hide-for-xlarge,tr.show-for-xlarge-down,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up,tr.hide-for-xxlarge,tr.show-for-xxlarge-down{display:table-row}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.hide-for-medium-down,td.hide-for-medium-down,th.show-for-large-only,td.show-for-large-only,th.show-for-large-up,td.show-for-large-up,th.show-for-large,td.show-for-large,th.show-for-large-down,td.show-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.hide-for-xlarge-up,td.hide-for-xlarge-up,th.hide-for-xlarge,td.hide-for-xlarge,th.show-for-xlarge-down,td.show-for-xlarge-down,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up,th.hide-for-xxlarge,td.hide-for-xxlarge,th.show-for-xxlarge-down,td.show-for-xxlarge-down{display:table-cell !important}}@media only screen and (min-width: 90.0625em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.hide-for-medium-only,.show-for-medium-up,.hide-for-medium,.hide-for-medium-down,.hide-for-large-only,.show-for-large-up,.hide-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.show-for-xlarge,.show-for-xlarge-down,.hide-for-xxlarge-only,.hide-for-xxlarge-up,.hide-for-xxlarge,.show-for-xxlarge-down{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.show-for-medium-only,.hide-for-medium-up,.show-for-medium,.show-for-medium-down,.show-for-large-only,.hide-for-large-up,.show-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xlarge,.hide-for-xlarge-down,.show-for-xxlarge-only,.show-for-xxlarge-up,.show-for-xxlarge,.hide-for-xxlarge-down{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.hidden-for-medium-only,.visible-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.hidden-for-large-only,.visible-for-large-up,.hidden-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xlarge,.visible-for-xlarge-down,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up,.hidden-for-xxlarge,.visible-for-xxlarge-down{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.visible-for-medium-only,.hidden-for-medium-up,.visible-for-medium,.visible-for-medium-down,.visible-for-large-only,.hidden-for-large-up,.visible-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xlarge,.hidden-for-xlarge-down,.visible-for-xxlarge-only,.visible-for-xxlarge-up,.visible-for-xxlarge,.hidden-for-xxlarge-down{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.hide-for-medium-only,table.show-for-medium-up,table.hide-for-medium,table.hide-for-medium-down,table.hide-for-large-only,table.show-for-large-up,table.hide-for-large,table.hide-for-large-down,table.show-for-xlarge-only,table.show-for-xlarge-up,table.show-for-xlarge,table.show-for-xlarge-down,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up,table.hide-for-xxlarge,table.show-for-xxlarge-down{display:table !important}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.hide-for-medium-only,thead.show-for-medium-up,thead.hide-for-medium,thead.hide-for-medium-down,thead.hide-for-large-only,thead.show-for-large-up,thead.hide-for-large,thead.hide-for-large-down,thead.show-for-xlarge-only,thead.show-for-xlarge-up,thead.show-for-xlarge,thead.show-for-xlarge-down,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up,thead.hide-for-xxlarge,thead.show-for-xxlarge-down{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.hide-for-medium-only,tbody.show-for-medium-up,tbody.hide-for-medium,tbody.hide-for-medium-down,tbody.hide-for-large-only,tbody.show-for-large-up,tbody.hide-for-large,tbody.hide-for-large-down,tbody.show-for-xlarge-only,tbody.show-for-xlarge-up,tbody.show-for-xlarge,tbody.show-for-xlarge-down,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up,tbody.hide-for-xxlarge,tbody.show-for-xxlarge-down{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.hide-for-medium-only,tr.show-for-medium-up,tr.hide-for-medium,tr.hide-for-medium-down,tr.hide-for-large-only,tr.show-for-large-up,tr.hide-for-large,tr.hide-for-large-down,tr.show-for-xlarge-only,tr.show-for-xlarge-up,tr.show-for-xlarge,tr.show-for-xlarge-down,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up,tr.hide-for-xxlarge,tr.show-for-xxlarge-down{display:table-row}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.hide-for-medium-down,td.hide-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.show-for-large-up,td.show-for-large-up,th.hide-for-large,td.hide-for-large,th.hide-for-large-down,td.hide-for-large-down,th.show-for-xlarge-only,td.show-for-xlarge-only,th.show-for-xlarge-up,td.show-for-xlarge-up,th.show-for-xlarge,td.show-for-xlarge,th.show-for-xlarge-down,td.show-for-xlarge-down,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up,th.hide-for-xxlarge,td.hide-for-xxlarge,th.show-for-xxlarge-down,td.show-for-xxlarge-down{display:table-cell !important}}@media only screen and (min-width: 120.0625em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.hide-for-medium-only,.show-for-medium-up,.hide-for-medium,.hide-for-medium-down,.hide-for-large-only,.show-for-large-up,.hide-for-large,.hide-for-large-down,.hide-for-xlarge-only,.show-for-xlarge-up,.hide-for-xlarge,.hide-for-xlarge-down,.show-for-xxlarge-only,.show-for-xxlarge-up,.show-for-xxlarge,.show-for-xxlarge-down{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.show-for-medium-only,.hide-for-medium-up,.show-for-medium,.show-for-medium-down,.show-for-large-only,.hide-for-large-up,.show-for-large,.show-for-large-down,.show-for-xlarge-only,.hide-for-xlarge-up,.show-for-xlarge,.show-for-xlarge-down,.hide-for-xxlarge-only,.hide-for-xxlarge-up,.hide-for-xxlarge,.hide-for-xxlarge-down{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.hidden-for-medium-only,.visible-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.hidden-for-large-only,.visible-for-large-up,.hidden-for-large,.hidden-for-large-down,.hidden-for-xlarge-only,.visible-for-xlarge-up,.hidden-for-xlarge,.hidden-for-xlarge-down,.visible-for-xxlarge-only,.visible-for-xxlarge-up,.visible-for-xxlarge,.visible-for-xxlarge-down{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.visible-for-medium-only,.hidden-for-medium-up,.visible-for-medium,.visible-for-medium-down,.visible-for-large-only,.hidden-for-large-up,.visible-for-large,.visible-for-large-down,.visible-for-xlarge-only,.hidden-for-xlarge-up,.visible-for-xlarge,.visible-for-xlarge-down,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up,.hidden-for-xxlarge,.hidden-for-xxlarge-down{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.hide-for-medium-only,table.show-for-medium-up,table.hide-for-medium,table.hide-for-medium-down,table.hide-for-large-only,table.show-for-large-up,table.hide-for-large,table.hide-for-large-down,table.hide-for-xlarge-only,table.show-for-xlarge-up,table.hide-for-xlarge,table.hide-for-xlarge-down,table.show-for-xxlarge-only,table.show-for-xxlarge-up,table.show-for-xxlarge,table.show-for-xxlarge-down{display:table !important}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.hide-for-medium-only,thead.show-for-medium-up,thead.hide-for-medium,thead.hide-for-medium-down,thead.hide-for-large-only,thead.show-for-large-up,thead.hide-for-large,thead.hide-for-large-down,thead.hide-for-xlarge-only,thead.show-for-xlarge-up,thead.hide-for-xlarge,thead.hide-for-xlarge-down,thead.show-for-xxlarge-only,thead.show-for-xxlarge-up,thead.show-for-xxlarge,thead.show-for-xxlarge-down{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.hide-for-medium-only,tbody.show-for-medium-up,tbody.hide-for-medium,tbody.hide-for-medium-down,tbody.hide-for-large-only,tbody.show-for-large-up,tbody.hide-for-large,tbody.hide-for-large-down,tbody.hide-for-xlarge-only,tbody.show-for-xlarge-up,tbody.hide-for-xlarge,tbody.hide-for-xlarge-down,tbody.show-for-xxlarge-only,tbody.show-for-xxlarge-up,tbody.show-for-xxlarge,tbody.show-for-xxlarge-down{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.hide-for-medium-only,tr.show-for-medium-up,tr.hide-for-medium,tr.hide-for-medium-down,tr.hide-for-large-only,tr.show-for-large-up,tr.hide-for-large,tr.hide-for-large-down,tr.hide-for-xlarge-only,tr.show-for-xlarge-up,tr.hide-for-xlarge,tr.hide-for-xlarge-down,tr.show-for-xxlarge-only,tr.show-for-xxlarge-up,tr.show-for-xxlarge,tr.show-for-xxlarge-down{display:table-row}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.hide-for-medium-down,td.hide-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.show-for-large-up,td.show-for-large-up,th.hide-for-large,td.hide-for-large,th.hide-for-large-down,td.hide-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.show-for-xlarge-up,td.show-for-xlarge-up,th.hide-for-xlarge,td.hide-for-xlarge,th.hide-for-xlarge-down,td.hide-for-xlarge-down,th.show-for-xxlarge-only,td.show-for-xxlarge-only,th.show-for-xxlarge-up,td.show-for-xxlarge-up,th.show-for-xxlarge,td.show-for-xxlarge,th.show-for-xxlarge-down,td.show-for-xxlarge-down{display:table-cell !important}}.show-for-landscape,.hide-for-portrait{display:inherit !important}.hide-for-landscape,.show-for-portrait{display:none !important}table.hide-for-landscape,table.show-for-portrait{display:table !important}thead.hide-for-landscape,thead.show-for-portrait{display:table-header-group !important}tbody.hide-for-landscape,tbody.show-for-portrait{display:table-row-group !important}tr.hide-for-landscape,tr.show-for-portrait{display:table-row !important}td.hide-for-landscape,td.show-for-portrait,th.hide-for-landscape,th.show-for-portrait{display:table-cell !important}@media only screen and (orientation: landscape){.show-for-landscape,.hide-for-portrait{display:inherit !important}.hide-for-landscape,.show-for-portrait{display:none !important}table.show-for-landscape,table.hide-for-portrait{display:table !important}thead.show-for-landscape,thead.hide-for-portrait{display:table-header-group !important}tbody.show-for-landscape,tbody.hide-for-portrait{display:table-row-group !important}tr.show-for-landscape,tr.hide-for-portrait{display:table-row !important}td.show-for-landscape,td.hide-for-portrait,th.show-for-landscape,th.hide-for-portrait{display:table-cell !important}}@media only screen and (orientation: portrait){.show-for-portrait,.hide-for-landscape{display:inherit !important}.hide-for-portrait,.show-for-landscape{display:none !important}table.show-for-portrait,table.hide-for-landscape{display:table !important}thead.show-for-portrait,thead.hide-for-landscape{display:table-header-group !important}tbody.show-for-portrait,tbody.hide-for-landscape{display:table-row-group !important}tr.show-for-portrait,tr.hide-for-landscape{display:table-row !important}td.show-for-portrait,td.hide-for-landscape,th.show-for-portrait,th.hide-for-landscape{display:table-cell !important}}.show-for-touch{display:none !important}.hide-for-touch{display:inherit !important}.touch .show-for-touch{display:inherit !important}.touch .hide-for-touch{display:none !important}table.hide-for-touch{display:table !important}.touch table.show-for-touch{display:table !important}thead.hide-for-touch{display:table-header-group !important}.touch thead.show-for-touch{display:table-header-group !important}tbody.hide-for-touch{display:table-row-group !important}.touch tbody.show-for-touch{display:table-row-group !important}tr.hide-for-touch{display:table-row !important}.touch tr.show-for-touch{display:table-row !important}td.hide-for-touch{display:table-cell !important}.touch td.show-for-touch{display:table-cell !important}th.hide-for-touch{display:table-cell !important}.touch th.show-for-touch{display:table-cell !important}.show-for-sr{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}.show-on-focus{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}.show-on-focus:focus,.show-on-focus:active{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.print-only{display:none !important}@media print{*{background:transparent !important;box-shadow:none !important;color:#000000 !important;text-shadow:none !important}.show-for-print{display:block}.hide-for-print{display:none}table.show-for-print{display:table !important}thead.show-for-print{display:table-header-group !important}tbody.show-for-print{display:table-row-group !important}tr.show-for-print{display:table-row !important}td.show-for-print{display:table-cell !important}th.show-for-print{display:table-cell !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.hide-on-print{display:none !important}.print-only{display:block !important}.hide-for-print{display:none !important}.show-for-print{display:inherit !important}}@media print{.show-for-print{display:block}.hide-for-print{display:none}table.show-for-print{display:table !important}thead.show-for-print{display:table-header-group !important}tbody.show-for-print{display:table-row-group !important}tr.show-for-print{display:table-row !important}td.show-for-print{display:table-cell !important}th.show-for-print{display:table-cell !important}}@media not print{.show-for-print{display:none !important}}div#pagetitle{padding-left:1rem;padding-right:1rem;font-size:larger}a#pagetitle{color:#bdbfd2;font-size:smaller}.top-bar .name{padding-top:0.5em}div#toc-container{min-width:35%;float:right;display:block;margin:1em}div.alert-box{display:flex !important}h1{border-bottom:2px solid black}h2{border-bottom:1px solid black}div#article_content{margin-bottom:3em;max-width:1000px}div#article_disqus{margin-bottom:3em;max-width:1000px}div#article_metadata{margin-bottom:3em;max-width:1000px}div#footer{position:fixed;height:2em;bottom:0;color:#aaa;width:100%;background-color:#333333;margin-top:0.25rem;font-size:0.9rem}.gist-file{margin-bottom:1em !important;margin-top:1em !important;border-radius:0px !important}.search-site{margin-bottom:1rem}.navbar-buttons{display:flex;flex-direction:row;justify-content:space-evenly}.navbar-icon-link{border-radius:50%;margin-top:0.25rem;padding:5px}div.sidebar{background-color:#FFFFFF}.side-nav li a:not(.button){color:#008CBA}li.button{background-color:#FFFFFF;padding:0;text-align:left}.sidebar-link{font-size:0.9rem}@media (max-width: 600px){div.not-mobile{display:none}}@media (min-width: 600px){div.mobile{display:none}}.navbar-background{background-image:linear-gradient(-90deg, #0078a0, #fff);margin-bottom:0.5rem;display:flex;flex-direction:row}#search-input{background-image:url(/img/search.png);background-repeat:no-repeat;background-size:1.3rem;background-position:0.3rem;padding-left:2rem}.no-margin{margin-left:0}.accordion-navigation>a:after{content:"↡";padding-left:5px;float:right;font-size:20px}.accordion-navigation.active>a:after{content:"↟"}ul.accordion{margin-left:0}#article_title{font-size:50px;font-family:"Linux Libertine", Roboto, Georgia, Times, serif;line-height:1.3;margin-bottom:0.25em;padding:0}#siteSub{font-size:11px}#mw-indicator-featured-star{position:relative;float:right;margin-top:-35px}#catlinks{text-align:left;margin-bottom:30px}.catlinks{border:1px solid #a2a9b1;background-color:#f8f9fa;padding:5px;margin-top:1em;clear:both;width:inherit}.catlinks ul{display:inline;padding:0;list-style:none none}.catlinks li{display:inline-block;line-height:1.1em;padding:0 0.4em;border-left:1pt solid #aaa}.catlinks li:first-child{padding-left:0.2em;border-left:0;margin-left:-20px}#hidden-catlinks{display:none}#toc,.toc,.mw-warning{background-color:#F9F9F9;border:1px solid #AAAAAA;font-size:95%;padding:5px;width:-webkit-fill-available}#toc h2,.toc h2{border:medium none;display:inline;font-size:100%;font-weight:bold;padding:0}#toc #toctitle,.toc #toctitle,#toc .toctitle,.toc .toctitle{text-align:center;margin:0 8px 4px 14px;padding-top:8px;line-height:1.2;overflow:hidden}#toc ul,.toc ul{list-style-image:none;list-style-type:none;margin:0 8px 7px 14px;padding-left:0;text-align:left}#toc ul ul,.toc ul ul{margin:0 0 0 2em}#toc .toctoggle,.toc .toctoggle{font-size:94%}#toc ul li{list-style-type:none;padding-left:0}#toc-container{float:none !important;margin-bottom:10px;display:block}div#quoteada{background-color:#7EC0D6;border:1px solid #0078a0;padding:1rem}div[class="highlight"]{margin-top:1rem;margin-bottom:1rem}code[class*="language-"]{color:black;padding-left:0;padding-right:0;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;text-align:left;padding:1rem;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:unset;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*="language-"]{color:black;border-color:grey;padding:0.5rem;border-width:1px;border-style:solid;border-radius:5px;padding:1rem;background:none;text-shadow:0 1px white;font-family:Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;text-align:left;word-spacing:normal;word-break:normal;word-wrap:normal;display:flex;line-height:normal;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*="language-"]::-moz-selection,pre[class*="language-"] ::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*="language-"]::-moz-selection,code[class*="language-"] ::-moz-selection{text-shadow:none;background:#b3d4fc}pre[class*="language-"]::selection,pre[class*="language-"] ::selection{text-shadow:none;background:#b3d4fc}code[class*="language-"]::selection,code[class*="language-"] ::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*="language-"],pre[class*="language-"]{text-shadow:none}}pre[class*="language-"]{padding:0.2em;margin:0.2em 0;overflow:auto}:not(pre)>code[class*="language-"],pre[class*="language-"]{background:#f5f2f0}:not(pre)>code[class*="language-"]{padding:.1em;border-radius:.3em;white-space:normal}.token.comment,.token.prolog,.token.doctype,.token.cdata{color:slategray}.token.punctuation{color:#999}.namespace{opacity:.7}.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol,.token.deleted{color:#905}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.inserted{color:#690}.token.operator,.token.entity,.token.url{color:#a67f59}.language-css .token.string,.style .token.string{color:#a67f59}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.function{color:#DD4A68}.token.regex,.token.important,.token.variable{color:#e90}.token.important,.token.bold{font-weight:bold}.token.italic{font-style:italic}.token.entity{cursor:help}.highlighter-rouge:not([class^="language-"]){color:crimson;font-size:90%;background-color:#f8f9fa;border-radius:.25rem;padding:.2rem .4rem}div.gist table{table-layout:initial} diff --git a/assets/app-1e946f931f577cd478e6e6610915be9d.css.gz b/assets/app-1e946f931f577cd478e6e6610915be9d.css.gz new file mode 100644 index 0000000000..ba0d9bbfe3 Binary files /dev/null and b/assets/app-1e946f931f577cd478e6e6610915be9d.css.gz differ diff --git a/assets/foundation/foundation-9cdbe0bbce183118de08f9938e53d976.js b/assets/foundation/foundation-9cdbe0bbce183118de08f9938e53d976.js new file mode 100644 index 0000000000..d50749efd9 --- /dev/null +++ b/assets/foundation/foundation-9cdbe0bbce183118de08f9938e53d976.js @@ -0,0 +1 @@ +!function(l,u,a,s){"use strict";function i(t){return("string"==typeof t||t instanceof String)&&(t=t.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g,"")),t}(function(t){for(var e=t.length,i=l("head");e--;)0===i.has("."+t[e]).length&&i.append('')})(["foundation-mq-small","foundation-mq-small-only","foundation-mq-medium","foundation-mq-medium-only","foundation-mq-large","foundation-mq-large-only","foundation-mq-xlarge","foundation-mq-xlarge-only","foundation-mq-xxlarge","foundation-data-attribute-namespace"]),l(function(){"undefined"!=typeof FastClick&&"undefined"!=typeof a.body&&FastClick.attach(a.body)});var c=function(t,e){if("string"!=typeof t)return l(t,e);if(e){var i;if(e.jquery){if(!(i=e[0]))return e}else i=e;return l(i.querySelectorAll(t))}return l(a.querySelectorAll(t))},e=function(t){var e=[];return t||e.push("data"),0").appendTo("head")[0].sheet,global:{namespace:s},init:function(t,e,i,n,a){var s=[t,i,n,a],r=[];if(this.rtl=/rtl/i.test(c("html").attr("dir")),this.scope=t||this.scope,this.set_namespace(),e&&"string"==typeof e&&!/reflow/i.test(e))this.libs.hasOwnProperty(e)&&r.push(this.init_lib(e,s));else for(var o in this.libs)r.push(this.init_lib(o,e));return c(u).load(function(){c(u).trigger("resize.fndtn.clearing").trigger("resize.fndtn.dropdown").trigger("resize.fndtn.equalizer").trigger("resize.fndtn.interchange").trigger("resize.fndtn.joyride").trigger("resize.fndtn.magellan").trigger("resize.fndtn.topbar").trigger("resize.fndtn.slider")}),t},init_lib:function(t,e){return this.libs.hasOwnProperty(t)?(this.patch(this.libs[t]),e&&e.hasOwnProperty(t)?("undefined"!=typeof this.libs[t].settings?l.extend(!0,this.libs[t].settings,e[t]):"undefined"!=typeof this.libs[t].defaults&&l.extend(!0,this.libs[t].defaults,e[t]),this.libs[t].init.apply(this.libs[t],[this.scope,e[t]])):(e=e instanceof Array?e:new Array(e),this.libs[t].init.apply(this.libs[t],e))):function(){}},patch:function(t){t.scope=this.scope,t.namespace=this.global.namespace,t.rtl=this.rtl,t.data_options=this.utils.data_options,t.attr_name=e,t.add_namespace=n,t.bindings=r,t.S=this.utils.S},inherit:function(t,e){for(var i=e.split(" "),n=i.length;n--;)this.utils.hasOwnProperty(i[n])&&(t[i[n]]=this.utils[i[n]])},set_namespace:function(){var t=this.global.namespace===s?l(".foundation-data-attribute-namespace").css("font-family"):this.global.namespace;this.global.namespace=t===s||/false/i.test(t)?"":t},libs:{},utils:{S:c,throttle:function(i,n){var a=null;return function(){var t=this,e=arguments;null==a&&(a=setTimeout(function(){i.apply(t,e),a=null},n))}},debounce:function(a,s,r){var o,u;return function(){var t=this,e=arguments,i=function(){o=null,r||(u=a.apply(t,e))},n=r&&!o;return clearTimeout(o),o=setTimeout(i,s),n&&(u=a.apply(t,e)),u}},data_options:function(t,i){function e(t){return!isNaN(t-0)&&null!==t&&""!==t&&!1!==t&&!0!==t}function n(t){return"string"==typeof t?l.trim(t):t}i=i||"options";var a,s,r,o={},u=function(t){var e=Foundation.global.namespace;return 0'),Foundation.media_queries[t]=i(l("."+e).css("font-family")))},add_custom_rule:function(t,e){e===s&&Foundation.stylesheet?Foundation.stylesheet.insertRule(t,Foundation.stylesheet.cssRules.length):Foundation.media_queries[e]!==s&&Foundation.stylesheet.insertRule("@media "+Foundation.media_queries[e]+"{ "+t+" }",Foundation.stylesheet.cssRules.length)},image_loaded:function(t,e){function i(t){for(var e=t.length-1;0<=e;e--)if(t.attr("height")===s)return!1;return!0}var n=this,a=t.length;(0===a||i(t))&&e(t),t.each(function(){o(n.S(this),function(){0===(a-=1)&&e(t)})})},random_str:function(){return this.fidx||(this.fidx=0),this.prefix=this.prefix||[this.name||"F",(+new Date).toString(36)].join("-"),this.prefix+(this.fidx++).toString(36)},match:function(t){return u.matchMedia(t).matches},is_small_up:function(){return this.match(Foundation.media_queries.small)},is_medium_up:function(){return this.match(Foundation.media_queries.medium)},is_large_up:function(){return this.match(Foundation.media_queries.large)},is_xlarge_up:function(){return this.match(Foundation.media_queries.xlarge)},is_xxlarge_up:function(){return this.match(Foundation.media_queries.xxlarge)},is_small_only:function(){return!(this.is_medium_up()||this.is_large_up()||this.is_xlarge_up()||this.is_xxlarge_up())},is_medium_only:function(){return this.is_medium_up()&&!this.is_large_up()&&!this.is_xlarge_up()&&!this.is_xxlarge_up()},is_large_only:function(){return this.is_medium_up()&&this.is_large_up()&&!this.is_xlarge_up()&&!this.is_xxlarge_up()},is_xlarge_only:function(){return this.is_medium_up()&&this.is_large_up()&&this.is_xlarge_up()&&!this.is_xxlarge_up()},is_xxlarge_only:function(){return this.is_medium_up()&&this.is_large_up()&&this.is_xlarge_up()&&this.is_xxlarge_up()}}},l.fn.foundation=function(){var t=Array.prototype.slice.call(arguments,0);return this.each(function(){return Foundation.init.apply(Foundation,[this].concat(t)),this})}}(jQuery,window,window.document); \ No newline at end of file diff --git a/assets/foundation/foundation-9cdbe0bbce183118de08f9938e53d976.js.gz b/assets/foundation/foundation-9cdbe0bbce183118de08f9938e53d976.js.gz new file mode 100644 index 0000000000..ddbe130186 Binary files /dev/null and b/assets/foundation/foundation-9cdbe0bbce183118de08f9938e53d976.js.gz differ diff --git a/assets/foundation/foundation.abide-89a2bdc8d7b0219f70b26edf2ae6887e.js b/assets/foundation/foundation.abide-89a2bdc8d7b0219f70b26edf2ae6887e.js new file mode 100644 index 0000000000..458cf78db3 --- /dev/null +++ b/assets/foundation/foundation.abide-89a2bdc8d7b0219f70b26edf2ae6887e.js @@ -0,0 +1 @@ +!function(y,t,r){"use strict";Foundation.libs.abide={name:"abide",version:"5.5.2",settings:{live_validate:!0,validate_on_blur:!0,focus_on_invalid:!0,error_labels:!0,error_class:"error",timeout:1e3,patterns:{alpha:/^[a-zA-Z]+$/,alpha_numeric:/^[a-zA-Z0-9]+$/,integer:/^[-+]?\d+$/,number:/^[-+]?\d*(?:[\.\,]\d+)?$/,card:/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/,cvv:/^([0-9]){3,4}$/,email:/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/,url:/^(https?|ftp|file|ssh):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+~%\/\.\w]+)?\??([-\+=&;%@\.\w]+)?#?([\w]+)?)?/,domain:/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,8}$/,datetime:/^([0-2][0-9]{3})\-([0-1][0-9])\-([0-3][0-9])T([0-5][0-9])\:([0-5][0-9])\:([0-5][0-9])(Z|([\-\+]([0-1][0-9])\:00))$/,date:/(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))$/,time:/^(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}$/,dateISO:/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,month_day_year:/^(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.]\d{4}$/,day_month_year:/^(0[1-9]|[12][0-9]|3[01])[- \/.](0[1-9]|1[012])[- \/.]\d{4}$/,color:/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/},validators:{equalTo:function(t){return r.getElementById(t.getAttribute(this.add_namespace("data-equalto"))).value===t.value}}},timer:null,init:function(t,e,a){this.bindings(e,a)},events:function(t){function e(t,e){clearTimeout(a.timer),a.timer=setTimeout(function(){a.validate([t],e)}.bind(t),r.timeout)}var a=this,i=a.S(t).attr("novalidate","novalidate"),r=i.data(this.attr_name(!0)+"-init")||{};this.invalid_attr=this.add_namespace("data-invalid"),i.off(".abide").on("submit.fndtn.abide",function(t){var e=/ajax/i.test(a.S(this).attr(a.attr_name()));return a.validate(a.S(this).find("input, textarea, select").not(":hidden, [data-abide-ignore]").get(),t,e)}).on("validate.fndtn.abide",function(t){"manual"===r.validate_on&&a.validate([t.target],t)}).on("reset",function(t){return a.reset(y(this),t)}).find("input, textarea, select").not(":hidden, [data-abide-ignore]").off(".abide").on("blur.fndtn.abide change.fndtn.abide",function(t){r.validate_on_blur&&!0===r.validate_on_blur&&e(this,t),"change"===r.validate_on&&e(this,t)}).on("keydown.fndtn.abide",function(t){r.live_validate&&!0===r.live_validate&&9!=t.which&&e(this,t),"tab"===r.validate_on&&9===t.which?e(this,t):"change"===r.validate_on&&e(this,t)}).on("focus",function(t){navigator.userAgent.match(/iPad|iPhone|Android|BlackBerry|Windows Phone|webOS/i)&&y("html, body").animate({scrollTop:y(t.target).offset().top},100)})},reset:function(t){var e=this;t.removeAttr(e.invalid_attr),y("["+e.invalid_attr+"]",t).removeAttr(e.invalid_attr),y("."+e.settings.error_class,t).not("small").removeClass(e.settings.error_class),y(":input",t).not(":button, :submit, :reset, :hidden, [data-abide-ignore]").val("").removeAttr(e.invalid_attr)},validate:function(t,e,a){for(var i=this.parse_patterns(t),r=i.length,s=this.S(t[0]).closest("form"),n=/submit/.test(e.type),l=0;l dd > a, ["+this.attr_name()+"] > li > a",function(t){var a=d(this).closest("["+l.attr_name()+"]"),e=l.attr_name()+"="+a.attr(l.attr_name()),n=a.data(l.attr_name(!0)+"-init")||l.settings,i=d("#"+this.href.split("#")[1]),s=o("> dd, > li",a),c=s.children("."+n.content_class),r=c.filter("."+n.active_class);if(t.preventDefault(),a.attr(l.attr_name())&&(c=c.add("["+e+"] dd > ."+n.content_class+", ["+e+"] li > ."+n.content_class),s=s.add("["+e+"] dd, ["+e+"] li")),n.toggleable&&i.is(r))return i.parent("dd, li").toggleClass(n.active_class,!1),i.toggleClass(n.active_class,!1),d(this).attr("aria-expanded",function(t,a){return"true"===a?"false":"true"}),n.callback(i),i.triggerHandler("toggled",[a]),void a.triggerHandler("toggled",[i]);n.multi_expand||(c.removeClass(n.active_class),s.removeClass(n.active_class),s.children("a").attr("aria-expanded","false")),i.addClass(n.active_class).parent().addClass(n.active_class),n.callback(i),i.triggerHandler("toggled",[a]),a.triggerHandler("toggled",[i]),d(this).attr("aria-expanded","true")})},create:function(t){var a=this,e=t,n=o("> .accordion-navigation",e),i=e.data(a.attr_name(!0)+"-init")||a.settings;n.children("a").attr("aria-expanded","false"),n.has("."+i.content_class+"."+i.active_class).children("a").attr("aria-expanded","true"),i.multi_expand&&t.attr("aria-multiselectable","true")},off:function(){},reflow:function(){}}}(jQuery,window,window.document); \ No newline at end of file diff --git a/assets/foundation/foundation.accordion-fb975cac4e1d51205357ccef64ad87f4.js.gz b/assets/foundation/foundation.accordion-fb975cac4e1d51205357ccef64ad87f4.js.gz new file mode 100644 index 0000000000..6ee63553ad Binary files /dev/null and b/assets/foundation/foundation.accordion-fb975cac4e1d51205357ccef64ad87f4.js.gz differ diff --git a/assets/foundation/foundation.alert-09f0ede105a8181ae99c1e952f89ca3b.js b/assets/foundation/foundation.alert-09f0ede105a8181ae99c1e952f89ca3b.js new file mode 100644 index 0000000000..50c0fabb87 --- /dev/null +++ b/assets/foundation/foundation.alert-09f0ede105a8181ae99c1e952f89ca3b.js @@ -0,0 +1 @@ +!function(t){"use strict";Foundation.libs.alert={name:"alert",version:"5.5.2",settings:{callback:function(){}},init:function(t,n,i){this.bindings(n,i)},events:function(){var e=this,s=this.S;t(this.scope).off(".alert").on("click.fndtn.alert","["+this.attr_name()+"] .close",function(t){var n=s(this).closest("["+e.attr_name()+"]"),i=n.data(e.attr_name(!0)+"-init")||e.settings;t.preventDefault(),Modernizr.csstransitions?(n.addClass("alert-close"),n.on("transitionend webkitTransitionEnd oTransitionEnd",function(){s(this).trigger("close.fndtn.alert").remove(),i.callback()})):n.fadeOut(300,function(){s(this).trigger("close.fndtn.alert").remove(),i.callback()})})},reflow:function(){}}}(jQuery,window,window.document); \ No newline at end of file diff --git a/assets/foundation/foundation.alert-09f0ede105a8181ae99c1e952f89ca3b.js.gz b/assets/foundation/foundation.alert-09f0ede105a8181ae99c1e952f89ca3b.js.gz new file mode 100644 index 0000000000..75500a9f3e Binary files /dev/null and b/assets/foundation/foundation.alert-09f0ede105a8181ae99c1e952f89ca3b.js.gz differ diff --git a/assets/foundation/foundation.clearing-1720b58085d63e88f45a453bb9ad3e3b.js b/assets/foundation/foundation.clearing-1720b58085d63e88f45a453bb9ad3e3b.js new file mode 100644 index 0000000000..43fd992dd0 --- /dev/null +++ b/assets/foundation/foundation.clearing-1720b58085d63e88f45a453bb9ad3e3b.js @@ -0,0 +1 @@ +!function(f,e,v,s){"use strict";Foundation.libs.clearing={name:"clearing",version:"5.5.2",settings:{templates:{viewing:'×'},close_selectors:".clearing-close, div.clearing-blackout",open_selectors:"",skip_selector:"",touch_label:"",init:!1,locked:!1},init:function(t,i,e){var n=this;Foundation.inherit(this,"throttle image_loaded"),this.bindings(i,e),n.S(this.scope).is("["+this.attr_name()+"]")?this.assemble(n.S("li",this.scope)):n.S("["+this.attr_name()+"]",this.scope).each(function(){n.assemble(n.S("li",this))})},events:function(t){var r=this,l=r.S,i=f(".scroll-container");0');var e=i.detach(),n="";if(null!=e[0]){n=e[0].outerHTML;var a=this.S("#foundationClearingHolder"),s={grid:'",viewing:i.data(this.attr_name(!0)+"-init").templates.viewing},r='
'+s.viewing+s.grid+"
",l=this.settings.touch_label;Modernizr.touch&&(r=f(r).find(".clearing-touch-label").html(l).end()),a.after(r).remove()}}},open:function(t,e,n){function i(){setTimeout(function(){this.image_loaded(g,function(){1!==g.outerWidth()||d?a.call(this,g):i.call(this)}.bind(this))}.bind(this),100)}function a(t){var i=f(t);i.css("visibility","visible"),i.trigger("imageVisible"),r.css("overflow","hidden"),l.addClass("clearing-blackout"),c.addClass("clearing-container"),o.show(),this.fix_height(n).caption(s.S(".clearing-caption",o),s.S("img",n)).center_and_label(t,h).shift(e,n,function(){n.closest("li").siblings().removeClass("visible"),n.closest("li").addClass("visible")}),o.trigger("opened.fndtn.clearing")}var s=this,r=f(v.body),l=n.closest(".clearing-assembled"),c=s.S("div",l).first(),o=s.S(".visible-img",c),g=s.S("img",o).not(t),h=s.S(".clearing-touch-label",c),d=!1,u={};f("body").on("touchmove",function(t){t.preventDefault()}),g.error(function(){d=!0}),this.locked()||(o.trigger("open.fndtn.clearing"),(u=this.load(t)).interchange?g.attr("data-interchange",u.interchange).foundation("interchange","reflow"):g.attr("src",u.src).attr("data-interchange",""),g.css("visibility","hidden"),i.call(this))},close:function(t,i){t.preventDefault();var e,n,a,s=(a=f(i),/blackout/.test(a.selector)?a:a.closest(".clearing-blackout")),r=f(v.body);return i===t.target&&s&&(r.css("overflow",""),e=f("div",s).first(),(n=f(".visible-img",e)).trigger("close.fndtn.clearing"),this.settings.prev_index=0,f("ul["+this.attr_name()+"]",s).attr("style","").closest(".clearing-blackout").removeClass("clearing-blackout"),e.removeClass("clearing-container"),n.hide(),n.trigger("closed.fndtn.clearing")),f("body").off("touchmove"),!1},is_open:function(t){return 0i.outerHeight()&&t.addClass("fix-height")}).closest("ul").width(100*i.length+"%"),this},update_paddles:function(t){var i=(t=t.closest("li")).closest(".carousel").siblings(".visible-img");0this.settings.prev_index?"right":r-1t.offset().left+a&&t.offset().left-a>this.outerWidth()&&(i.missRight=!0,i.missLeft=!1),t.offset().left-this.outerWidth()<=0&&(i.missLeft=!0,i.missRight=!1)),i},top:function(t,e){var s=Foundation.libs.dropdown,i=s.dirs._base.call(this,t);return this.addClass("drop-top"),1==i.missTop&&(i.top=i.top+t.outerHeight()+this.outerHeight(),this.removeClass("drop-top")),1==i.missRight&&(i.left=i.left-this.outerWidth()+t.outerWidth()),(t.outerWidth()×',timer:'
',tip:'
',wrapper:'
',button:'',prev_button:'',modal:'
',expose:'
',expose_cover:'
'},expose_add_class:""},init:function(t,s,i){Foundation.inherit(this,"throttle random_str"),this.settings=this.settings||r.extend({},this.defaults,i||s),this.bindings(s,i)},go_next:function(){this.settings.$li.next().length<1?this.end():0 li"),this.settings.paused=!1,this.settings.attempts=0,this.settings.riding=!0,"function"!=typeof r.cookie&&(this.settings.cookie_monster=!1),(!this.settings.cookie_monster||this.settings.cookie_monster&&!r.cookie(this.settings.cookie_name))&&(this.settings.$tip_content.each(function(t){var s=r(this);this.settings=r.extend({},e.defaults,e.data_options(s));for(var i=o;i--;)e.settings[n[i]]=parseInt(e.settings[n[i]],10);e.create({$li:s,index:t})}),!this.settings.start_timer_on_click&&0t.offset().left]},visible:function(t){for(var s=t.length;s--;)if(t[s])return!1;return!0},nub_position:function(t,s,i){"auto"===s?t.addClass(i):t.addClass(s)},startTimer:function(){this.settings.$li.length?this.settings.automate=setTimeout(function(){this.hide(),this.show(),this.startTimer()}.bind(this),this.settings.timer):clearTimeout(this.settings.automate)},end:function(t){this.settings.cookie_monster&&r.cookie(this.settings.cookie_name,"ridden",{expires:this.settings.cookie_expires,domain:this.settings.cookie_domain}),0=i){var n=t.prev("["+o.add_namespace("data-magellan-expedition-clone")+"]");0===n.length&&((n=t.clone()).removeAttr(o.attr_name()),n.attr(o.add_namespace("data-magellan-expedition-clone"),""),t.before(n)),t.css({position:"fixed",top:a.fixed_top}).addClass("fixed")}else t.prev("["+o.add_namespace("data-magellan-expedition-clone")+"]").remove(),t.attr("style",e).css("position","").css("top","").removeClass("fixed")})},update_arrivals:function(){var o=this,s=h(t).scrollTop();h("["+this.attr_name()+"]",o.scope).each(function(){var e=h(this),i=e.data(o.attr_name(!0)+"-init"),t=o.offsets(e,s),a=e.find("["+o.add_namespace("data-magellan-arrival")+"]"),n=!1;t.each(function(t,a){if(a.viewport_offset>=a.top_offset)return e.find("["+o.add_namespace("data-magellan-arrival")+"]").not(a.arrival).removeClass(i.active_class),a.arrival.addClass(i.active_class),n=!0}),n||a.removeClass(i.active_class)})},offsets:function(i,t){var n=this,o=i.data(n.attr_name(!0)+"-init"),s=t;return i.find("["+n.add_namespace("data-magellan-arrival")+"]").map(function(){var t=h(this).data(n.data_attr("magellan-arrival")),a=h("["+n.add_namespace("data-magellan-destination")+"="+t+"]");if(0a.top_offset?1:0})},data_attr:function(t){return 0'),s=u.parent(),u.addClass(l.slides_container_class),l.stack_on_small&&s.addClass(l.stack_on_small_class),l.navigation_arrows&&(s.append(m('').addClass(l.prev_class)),s.append(m('').addClass(l.next_class))),l.timer&&((a=m("
").addClass(l.timer_container_class)).append(""),a.append(m("
").addClass(l.timer_progress_class)),a.addClass(l.timer_paused_class),s.append(a)),l.slide_number&&((e=m("
").addClass(l.slide_number_class)).append(" "+l.slide_number_text+" "),s.append(e)),l.bullets&&(i=m("
    ").addClass(l.bullets_container_class),s.append(i),i.wrap('
    '),_.slides().each(function(t){var e=m("
  1. ").attr("data-orbit-slide",t).on("click",_.link_bullet);i.append(e)}))},_._goto=function(e,i){if(e===p)return!1;"object"==typeof d&&d.restart();var s=_.slides(),t="next";if(!0,e=s.length){if(!l.circular)return!1;e=0}else if(e<0){if(!l.circular)return!1;e=s.length-1}var a=m(s.get(p)),n=m(s.get(e));a.css("zIndex",2),a.removeClass(l.active_slide_class),n.css("zIndex",4).addClass(l.active_slide_class),u.trigger("before-slide-change.fndtn.orbit"),l.before_slide_change(),_.update_active_link(e);var r=function(){var t=function(){p=e,!!1===i&&(d=_.create_timer()).start(),_.update_slide_number(p),u.trigger("after-slide-change.fndtn.orbit",[{slide_number:p,total_slides:s.length}]),l.after_slide_change(p,s.length)};u.outerHeight()!=n.outerHeight()&&l.variable_height?u.animate({height:n.outerHeight()},250,"linear",t):t()};if(1===s.length)return r(),!1;var o=function(){"next"===t&&c.next(a,n,r),"prev"===t&&c.prev(a,n,r)};n.outerHeight()>u.outerHeight()&&l.variable_height?u.animate({height:n.outerHeight()},250,"linear",o):o()},_.next=function(t){t.stopImmediatePropagation(),t.preventDefault(),_._goto(p+1)},_.prev=function(t){t.stopImmediatePropagation(),t.preventDefault(),_._goto(p-1)},_.link_custom=function(t){t.preventDefault();var e=m(this).attr("data-orbit-link");if("string"==typeof e&&""!=(e=m.trim(e))){var i=s.find("[data-orbit-slide="+e+"]");-1!=i.index()&&_._goto(i.index())}},_.link_bullet=function(){var t=m(this).attr("data-orbit-slide");if("string"==typeof t&&""!=(t=m.trim(t)))if(isNaN(parseInt(t))){var e=s.find("[data-orbit-slide="+t+"]");-1!=e.index()&&_._goto(e.index()+1)}else _._goto(parseInt(t))},_.timer_callback=function(){_._goto(p+1,!0)},_.compute_dimensions=function(){var t=m(_.slides().get(p)).outerHeight();l.variable_height||_.slides().each(function(){m(this).outerHeight()>t&&(t=m(this).outerHeight())}),u.height(t)},_.create_timer=function(){return new g(s.find("."+l.timer_container_class),l,_.timer_callback)},_.stop_timer=function(){"object"==typeof d&&d.stop()},_.toggle_timer=function(){s.find("."+l.timer_container_class).hasClass(l.timer_paused_class)?(void 0===d&&(d=_.create_timer()),d.start()):"object"==typeof d&&d.stop()},_.init=function(){_.build_markup(),l.timer&&(d=_.create_timer(),Foundation.utils.image_loaded(this.slides().children("img"),d.start)),c=new h(l,u),"slide"===l.animation&&(c=new f(l,u)),s.on("click","."+l.next_class,_.next),s.on("click","."+l.prev_class,_.prev),l.next_on_click&&s.on("click","."+l.slides_container_class+" [data-orbit-slide]",_.link_bullet),s.on("click",_.toggle_timer),l.swipe&&s.on("touchstart.fndtn.orbit",function(t){t.touches||(t=t.originalEvent);var e={start_page_x:t.touches[0].pageX,start_page_y:t.touches[0].pageY,start_time:(new Date).getTime(),delta_x:0,is_scrolling:o};s.data("swipe-transition",e),t.stopPropagation()}).on("touchmove.fndtn.orbit",function(t){if(t.touches||(t=t.originalEvent),!(1",{"class":this.settings.bg_class}).appendTo("body").hide());var n=0').parent();e.on("closed.fndtn.reveal.wrapped",function(){e.detach().appendTo(a),e.unwrap().unbind("closed.fndtn.reveal.wrapped")}),e.detach().appendTo(n)}var o=l(r.animation);if(o.animate||(this.locked=!1),o.pop){t.top=d(c).scrollTop()-e.data("offset")+"px";var i={top:d(c).scrollTop()+e.data("css-top")+"px",opacity:1};return setTimeout(function(){return e.css(t).animate(i,r.animation_speed,"linear",function(){s.locked=!1,e.trigger("opened.fndtn.reveal")}).addClass("open")},r.animation_speed/2)}if(o.fade){t.top=d(c).scrollTop()+e.data("css-top")+"px";i={opacity:1};return setTimeout(function(){return e.css(t).animate(i,r.animation_speed,"linear",function(){s.locked=!1,e.trigger("opened.fndtn.reveal")}).addClass("open")},r.animation_speed/2)}return e.css(t).show().css({opacity:1}).addClass("open").trigger("opened.fndtn.reveal")}var r;return l((r=this.settings).animation).fade?e.fadeIn(r.animation_speed/2):(this.locked=!1,e.show())},to_back:function(e){e.addClass("toback")},to_front:function(e){e.removeClass("toback")},hide:function(e,t){if(t){var n=e.data(this.attr_name(!0)+"-init"),s=this,a=l((n=n||this.settings).animation);if(a.animate||(this.locked=!1),a.pop){var o={top:-d(c).scrollTop()-e.data("offset")+"px",opacity:0};return setTimeout(function(){return e.animate(o,n.animation_speed,"linear",function(){s.locked=!1,e.css(t).trigger("closed.fndtn.reveal")}).removeClass("open")},n.animation_speed/2)}if(a.fade){o={opacity:0};return setTimeout(function(){return e.animate(o,n.animation_speed,"linear",function(){s.locked=!1,e.css(t).trigger("closed.fndtn.reveal")}).removeClass("open")},n.animation_speed/2)}return e.hide().css(t).removeClass("open").trigger("closed.fndtn.reveal")}return l((n=this.settings).animation).fade?e.fadeOut(n.animation_speed/2):e.hide()},close_video:function(e){var t=d(".flex-video",e.target),n=d("iframe",t);0 .active > a",this.scope).each(function(){n.default_tab_hashes.push(this.hash)}),n.entry_location=u.location.href,this.bindings(a,e),this.handle_location_hash_change()},events:function(){var e=this,n=this.S,i=function(t,a){n(a).closest("["+e.attr_name()+"]").data(e.attr_name(!0)+"-init").is_hover&&!Modernizr.touch||(t.preventDefault(),t.stopPropagation(),e.toggle_active_tab(n(a).parent()))};n(this.scope).off(".tab").on("keydown.fndtn.tab","["+this.attr_name()+"] > * > a",function(t){var a=this;9==(t.keyCode||t.which)&&(t.preventDefault(),i(t,a))}).on("click.fndtn.tab","["+this.attr_name()+"] > * > a",function(t){i(t,this)}).on("mouseenter.fndtn.tab","["+this.attr_name()+"] > * > a",function(){n(this).closest("["+e.attr_name()+"]").data(e.attr_name(!0)+"-init").is_hover&&e.toggle_active_tab(n(this).parent())}),n(u).on("hashchange.fndtn.tab",function(t){t.preventDefault(),e.handle_location_hash_change()})},handle_location_hash_change:function(){var s=this,r=this.S;r("["+this.attr_name()+"]",this.scope).each(function(){var t,a=r(this).data(s.attr_name(!0)+"-init");if(a.deep_linking)if(""!=(t=a.scroll_to_content?s.scope.location.hash:s.scope.location.hash.replace("fndtn-",""))){var e=r(t);if(e.hasClass("content")&&e.parent().hasClass("tabs-content"))s.toggle_active_tab(f("["+s.attr_name()+"] > * > a[href="+t+"]").parent());else{var n=e.closest(".content").attr("id");n!=g&&s.toggle_active_tab(f("["+s.attr_name()+"] > * > a[href=#"+n+"]").parent(),t)}}else for(var i=0;i * > a[href="+s.default_tab_hashes[i]+"]").parent())})},toggle_active_tab:function(t,a){var n=this,e=n.S,i=t.closest("["+this.attr_name()+"]"),s=t.find("a"),r=t.children("a").first(),o="#"+r.attr("href").split("#")[1],c=e(o),l=t.siblings(),h=i.data(this.attr_name(!0)+"-init"),d=function(t){var a,e=f(this),n=f(this).parents("li").prev().children('[role="tab"]'),i=f(this).parents("li").next().children('[role="tab"]');switch(t.keyCode){case 37:a=n;break;case 39:a=i;break;default:a=!1}a.length&&(e.attr({tabindex:"-1","aria-selected":null}),a.attr({tabindex:"0","aria-selected":!0}).focus()),f('[role="tabpanel"]').attr("aria-hidden","true"),f("#"+f(b.activeElement).attr("href").substring(1)).attr("aria-hidden",null)},_=function(t){var a=u.location.href===n.entry_location,e=h.scroll_to_content?n.default_tab_hashes[0]:a?u.location.hash:"fndtn-"+n.default_tab_hashes[0].replace("#","");a&&t===e||(u.location.hash=t)};r.data("tab-content")&&(c=e(o="#"+r.data("tab-content").split("#")[1])),h.deep_linking&&(h.scroll_to_content?(_(a||o),a==g||a==o?t.parent()[0].scrollIntoView():e(o)[0].scrollIntoView()):_(a!=g?"fndtn-"+a.replace("#",""):"fndtn-"+o.replace("#",""))),t.addClass(h.active_class).triggerHandler("opened"),s.attr({"aria-selected":"true",tabindex:0}),l.removeClass(h.active_class),l.find("a").attr({"aria-selected":"false",tabindex:-1}),c.siblings().removeClass(h.active_class).attr({"aria-hidden":"true",tabindex:-1}),c.addClass(h.active_class).attr("aria-hidden","false").removeAttr("tabindex"),h.callback(t),c.triggerHandler("toggled",[c]),i.triggerHandler("toggled",[t]),s.off("keydown").on("keydown",d)},data_attr:function(t){return 0'+e+''}},cache:{},init:function(t,e,o){Foundation.inherit(this,"random_str"),this.bindings(e,o)},should_show:function(t){var e=l.extend({},this.settings,this.data_options(t));return"all"===e.show_on||(!(!this.small()||"small"!==e.show_on)||(!(!this.medium()||"medium"!==e.show_on)||!(!this.large()||"large"!==e.show_on)))},medium:function(){return matchMedia(Foundation.media_queries.medium).matches},large:function(){return matchMedia(Foundation.media_queries.large).matches},events:function(t){function s(t,e,o){t.timer||(o?(t.timer=null,a.showTip(e)):t.timer=setTimeout(function(){t.timer=null,a.showTip(e)}.bind(t),a.settings.hover_delay))}function n(t,e){t.timer&&(clearTimeout(t.timer),t.timer=null),a.hide(e)}var a=this,r=a.S;a.create(this.S(t)),l(this.scope).off(".tooltip").on("mouseenter.fndtn.tooltip mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip","["+this.attr_name()+"]",function(t){var e=r(this),o=l.extend({},a.settings,a.data_options(e));if(Modernizr.touch&&/touchstart|MSPointerDown/i.test(t.type)&&r(t.target).is("a"))return!1;if(/mouse/i.test(t.type)&&a.ie_touch(t))return!1;if(e.hasClass("open"))Modernizr.touch&&/touchstart|MSPointerDown/i.test(t.type)&&t.preventDefault(),a.hide(e);else{if(o.disable_for_touch&&Modernizr.touch&&/touchstart|MSPointerDown/i.test(t.type))return;if(!o.disable_for_touch&&Modernizr.touch&&/touchstart|MSPointerDown/i.test(t.type)&&(t.preventDefault(),r(o.tooltip_class+".open").hide(),!0,0
").html(t.attr("title")).html())),n=this.inheritable_classes(t);s.addClass(n).appendTo(o.append_to),Modernizr.touch&&(s.append(''+o.touch_close_text+""),s.on("touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip",function(){e.hide(t)})),t.removeAttr("title").attr("title","")},reposition:function(t,e,o){var i,s,n,a;if(e.css("visibility","hidden").show(),i=t.data("width"),n=(s=e.children(".nub")).outerHeight(),s.outerHeight(),this.small()?e.css({width:"100%"}):e.css({width:i||"auto"}),(a=function(t,e,o,i,s){return t.css({top:e||"auto",bottom:i||"auto",left:s||"auto",right:o||"auto"}).end()})(e,t.offset().top+t.outerHeight()+10,"auto","auto",t.offset().left),this.small())a(e,t.offset().top+t.outerHeight()+10,"auto","auto",12.5,l(this.scope).width()),e.addClass("tip-override"),a(s,-n,"auto","auto",t.offset().left);else{var r=t.offset().left;Foundation.rtl&&(s.addClass("rtl"),r=t.offset().left+t.outerWidth()-e.outerWidth()),a(e,t.offset().top+t.outerHeight()+10,"auto","auto",r),s.attr("style")&&s.removeAttr("style"),e.removeClass("tip-override"),o&&-1'+i.touch_close_text+""),o.on("click.fndtn.tooltip.tapclose touchstart.fndtn.tooltip.tapclose MSPointerDown.fndtn.tooltip.tapclose",function(){e.hide(t)})),t.data("tooltip-open-event-type","touch")},show:function(t){var e=this.getTip(t);"touch"==t.data("tooltip-open-event-type")&&this.convert_to_touch(t),this.reposition(t,e,t.attr("class")),t.addClass("open"),e.fadeIn(150)},hide:function(t){var e=this.getTip(t);e.fadeOut(150,function(){e.find(".tap-to-close").remove(),e.off("click.fndtn.tooltip.tapclose MSPointerDown.fndtn.tapclose"),t.removeClass("open")})},off:function(){var e=this;this.S(this.scope).off(".fndtn.tooltip"),this.S(this.settings.tooltip_class).each(function(t){l("["+e.attr_name()+"]").eq(t).attr("title",l(this).text())}).remove()},reflow:function(){}}}(jQuery,window,window.document); \ No newline at end of file diff --git a/assets/foundation/foundation.tooltip-926551742e978e4456aa7ca8c6ffe334.js.gz b/assets/foundation/foundation.tooltip-926551742e978e4456aa7ca8c6ffe334.js.gz new file mode 100644 index 0000000000..62216e812b Binary files /dev/null and b/assets/foundation/foundation.tooltip-926551742e978e4456aa7ca8c6ffe334.js.gz differ diff --git a/assets/foundation/foundation.topbar-fa936a3a88514cb2c51c4ccf3fefaeb0.js b/assets/foundation/foundation.topbar-fa936a3a88514cb2c51c4ccf3fefaeb0.js new file mode 100644 index 0000000000..f6b83cecdf --- /dev/null +++ b/assets/foundation/foundation.topbar-fa936a3a88514cb2c51c4ccf3fefaeb0.js @@ -0,0 +1 @@ +!function(d,n,o){"use strict";Foundation.libs.topbar={name:"topbar",version:"5.5.2",settings:{index:0,start_offset:0,sticky_class:"sticky",custom_back_text:!0,back_text:"Back",mobile_show_parent_link:!0,is_hover:!0,scrolltop:!0,sticky_on:"all",dropdown_autoclose:!0},init:function(t,a,s){Foundation.inherit(this,"add_custom_rule register_media throttle");var e=this;e.register_media("topbar","foundation-mq-topbar"),this.bindings(a,s),e.S("["+this.attr_name()+"]",this.scope).each(function(){var t=d(this),a=t.data(e.attr_name(!0)+"-init");e.S("section, .top-bar-section",this);t.data("index",0);var s=t.parent();s.hasClass("fixed")||e.is_sticky(t,s,a)?(e.settings.sticky_class=a.sticky_class,(e.settings.sticky_topbar=t).data("height",s.outerHeight()),t.data("stickyoffset",s.offset().top)):t.data("height",t.outerHeight()),a.assembled||e.assemble(t),a.is_hover?e.S(".has-dropdown",t).addClass("not-click"):e.S(".has-dropdown",t).removeClass("not-click"),e.add_custom_rule(".f-topbar-fixed { padding-top: "+t.data("height")+"px }"),s.hasClass("fixed")&&e.S("body").addClass("f-topbar-fixed")})},is_sticky:function(t,a,s){var e=a.hasClass(s.sticky_class),i=matchMedia(Foundation.media_queries.small).matches,n=matchMedia(Foundation.media_queries.medium).matches,o=matchMedia(Foundation.media_queries.large).matches;return!(!e||"all"!==s.sticky_on)||(!(!(e&&this.small()&&-1!==s.sticky_on.indexOf("small")&&i)||n||o)||(!(!(e&&this.medium()&&-1!==s.sticky_on.indexOf("medium")&&i&&n)||o)||!!(e&&this.large()&&-1!==s.sticky_on.indexOf("large")&&i&&n&&o)))},toggle:function(t){var a,s=this,e=(a=t?s.S(t).closest("["+this.attr_name()+"]"):s.S("["+this.attr_name()+"]")).data(this.attr_name(!0)+"-init"),i=s.S("section, .top-bar-section",a);s.breakpoint()&&(s.rtl?(i.css({right:"0%"}),d(">.name",i).css({right:"100%"})):(i.css({left:"0%"}),d(">.name",i).css({left:"100%"})),s.S("li.moved",i).removeClass("moved"),a.data("index",0),a.toggleClass("expanded").css("height","")),e.scrolltop?a.hasClass("expanded")?a.parent().hasClass("fixed")&&(e.scrolltop?(a.parent().removeClass("fixed"),a.addClass("fixed"),s.S("body").removeClass("f-topbar-fixed"),n.scrollTo(0,0)):a.parent().removeClass("expanded")):a.hasClass("fixed")&&(a.parent().addClass("fixed"),a.removeClass("fixed"),s.S("body").addClass("f-topbar-fixed")):(s.is_sticky(a,a.parent(),e)&&a.parent().addClass("fixed"),a.parent().hasClass("fixed")&&(a.hasClass("expanded")?(a.addClass("fixed"),a.parent().addClass("expanded"),s.S("body").addClass("f-topbar-fixed")):(a.removeClass("fixed"),a.parent().removeClass("expanded"),s.update_sticky_positioning())))},timer:null,events:function(){var o=this,r=this.S;r(this.scope).off(".topbar").on("click.fndtn.topbar","["+this.attr_name()+"] .toggle-topbar",function(t){t.preventDefault(),o.toggle(this)}).on("click.fndtn.topbar contextmenu.fndtn.topbar",'.top-bar .top-bar-section li a[href^="#"],['+this.attr_name()+'] .top-bar-section li a[href^="#"]',function(){var t=d(this).closest("li"),a=t.closest("["+o.attr_name()+"]").data(o.attr_name(!0)+"-init");a.dropdown_autoclose&&a.is_hover&&d(this).closest(".hover").removeClass("hover");!o.breakpoint()||t.hasClass("back")||t.hasClass("has-dropdown")||o.toggle()}).on("click.fndtn.topbar","["+this.attr_name()+"] li.has-dropdown",function(t){var a=r(this),s=r(t.target),e=a.closest("["+o.attr_name()+"]").data(o.attr_name(!0)+"-init");s.data("revealId")?o.toggle():o.breakpoint()||e.is_hover&&!Modernizr.touch||(t.stopImmediatePropagation(),a.hasClass("hover")?(a.removeClass("hover").find("li").removeClass("hover"),a.parents("li.hover").removeClass("hover")):(a.addClass("hover"),d(a).siblings().removeClass("hover"),"A"===s[0].nodeName&&s.parent().hasClass("has-dropdown")&&t.preventDefault()))}).on("click.fndtn.topbar","["+this.attr_name()+"] .has-dropdown>a",function(t){if(o.breakpoint()){t.preventDefault();var a=r(this),s=a.closest("["+o.attr_name()+"]"),e=s.find("section, .top-bar-section"),i=(a.next(".dropdown").outerHeight(),a.closest("li"));s.data("index",s.data("index")+1),i.addClass("moved"),o.rtl?(e.css({right:-100*s.data("index")+"%"}),e.find(">.name").css({right:100*s.data("index")+"%"})):(e.css({left:-100*s.data("index")+"%"}),e.find(">.name").css({left:100*s.data("index")+"%"})),s.css("height",a.siblings("ul").outerHeight(!0)+s.data("height"))}}),r(n).off(".topbar").on("resize.fndtn.topbar",o.throttle(function(){o.resize.call(o)},50)).trigger("resize.fndtn.topbar").load(function(){r(this).trigger("resize.fndtn.topbar")}),r("body").off(".topbar").on("click.fndtn.topbar",function(t){0.name").css({right:100*s.data("index")+"%"})):(e.css({left:-100*s.data("index")+"%"}),e.find(">.name").css({left:100*s.data("index")+"%"})),0===s.data("index")?s.css("height",""):s.css("height",n.outerHeight(!0)+s.data("height")),setTimeout(function(){i.removeClass("moved")},300)}),r(this.scope).find(".dropdown a").focus(function(){d(this).parents(".has-dropdown").addClass("hover")}).blur(function(){d(this).parents(".has-dropdown").removeClass("hover")})},resize:function(){var n=this;n.S("["+this.attr_name()+"]").each(function(){var t,a=n.S(this),s=a.data(n.attr_name(!0)+"-init"),e=a.parent("."+n.settings.sticky_class);if(!n.breakpoint()){var i=a.hasClass("expanded");a.css("height","").removeClass("expanded").find("li").removeClass("hover"),i&&n.toggle(a)}n.is_sticky(a,e,s)&&(e.hasClass("fixed")?(e.removeClass("fixed"),t=e.offset().top,n.S(o.body).hasClass("f-topbar-fixed")&&(t-=a.data("height")),a.data("stickyoffset",t),e.addClass("fixed")):(t=e.offset().top,a.data("stickyoffset",t)))})},breakpoint:function(){return!matchMedia(Foundation.media_queries.topbar).matches},small:function(){return matchMedia(Foundation.media_queries.small).matches},medium:function(){return matchMedia(Foundation.media_queries.medium).matches},large:function(){return matchMedia(Foundation.media_queries.large).matches},assemble:function(t){var i=this,n=t.data(this.attr_name(!0)+"-init"),a=i.S("section, .top-bar-section",t);a.detach(),i.S(".has-dropdown>a",a).each(function(){var t,a=i.S(this),s=a.siblings(".dropdown"),e=a.attr("href");s.find(".title.back").length||(t=1==n.mobile_show_parent_link&&e?d('
  • "):d('
  • '),1==n.custom_back_text?d("h5>a",t).html(n.back_text):d("h5>a",t).html("« "+a.html()),s.prepend(t))}),a.appendTo(t),this.sticky(),this.assembled(t)},assembled:function(t){t.data(this.attr_name(!0),d.extend({},t.data(this.attr_name(!0)),{assembled:!0}))},height:function(t){var a=0,s=this;return d("> li",t).each(function(){a+=s.S(this).outerHeight(!0)}),a},sticky:function(){var t=this;this.S(n).on("scroll",function(){t.update_sticky_positioning()})},update_sticky_positioning:function(){var t="."+this.settings.sticky_class,a=this.S(n),s=this;if(s.settings.sticky_topbar&&s.is_sticky(this.settings.sticky_topbar,this.settings.sticky_topbar.parent(),this.settings)){var e=this.settings.sticky_topbar.data("stickyoffset")+this.settings.start_offset;s.S(t).hasClass("expanded")||(a.scrollTop()>e?s.S(t).hasClass("fixed")||(s.S(t).addClass("fixed"),s.S("body").addClass("f-topbar-fixed")):a.scrollTop()<=e&&s.S(t).hasClass("fixed")&&(s.S(t).removeClass("fixed"),s.S("body").removeClass("f-topbar-fixed")))}},off:function(){this.S(this.scope).off(".fndtn.topbar"),this.S(n).off(".fndtn.topbar")},reflow:function(){}}}(jQuery,window,window.document); \ No newline at end of file diff --git a/assets/foundation/foundation.topbar-fa936a3a88514cb2c51c4ccf3fefaeb0.js.gz b/assets/foundation/foundation.topbar-fa936a3a88514cb2c51c4ccf3fefaeb0.js.gz new file mode 100644 index 0000000000..d62420e93f Binary files /dev/null and b/assets/foundation/foundation.topbar-fa936a3a88514cb2c51c4ccf3fefaeb0.js.gz differ diff --git a/assets/jekyll-search-db248d3bf113e122870c09fd6d9b0592.js b/assets/jekyll-search-db248d3bf113e122870c09fd6d9b0592.js new file mode 100644 index 0000000000..3cbff91efe --- /dev/null +++ b/assets/jekyll-search-db248d3bf113e122870c09fd6d9b0592.js @@ -0,0 +1 @@ +!function e(u,o,a){function c(n,t){if(!o[n]){if(!u[n]){var r="function"==typeof require&&require;if(!t&&r)return r(n,!0);if(s)return s(n,!0);throw new Error("Cannot find module '"+n+"'")}var i=o[n]={exports:{}};u[n][0].call(i.exports,function(t){var e=u[n][1][t];return c(e||t)},i,i.exports,e,u,o,a)}return o[n].exports}for(var s="function"==typeof require&&require,t=0;t{title}
  • ',templateMiddleware:function(){},noResultsText:"No results found",limit:10,fuzzy:!1,exclude:[]},l=["searchInput","resultsContainer","json"],p=g("./Templater"),h=g("./Repository"),d=g("./JSONLoader"),m=g("./OptionsValidator")({required:l}),y=g("./utils");t.SimpleJekyllSearch=function S(t){0")).appendTo(t.documentElement))[0].contentDocument).write(),t.close(),n=x(e,t),$e.detach()),Ie[e]=n),n}function w(e,t,n){var r,i,o,s,a=e.style;return(n=n||ze(e))&&(s=n.getPropertyValue(t)||n[t]),n&&(""!==s||Z.contains(e.ownerDocument,e)||(s=Z.style(e,t)),_e.test(s)&&Be.test(t)&&(r=a.width,i=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=s,s=n.width,a.width=r,a.minWidth=i,a.maxWidth=o)),s!==undefined?s+"":s}function T(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}function C(e,t){if(t in e)return t;for(var n=t[0].toUpperCase()+t.slice(1),r=t,i=Qe.length;i--;)if((t=Qe[i]+n)in e)return t;return r}function N(e,t,n){var r=Ue.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function k(e,t,n,r,i){for(var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;o<4;o+=2)"margin"===n&&(s+=Z.css(e,n+Ce[o],!0,i)),r?("content"===n&&(s-=Z.css(e,"padding"+Ce[o],!0,i)),"margin"!==n&&(s-=Z.css(e,"border"+Ce[o]+"Width",!0,i))):(s+=Z.css(e,"padding"+Ce[o],!0,i),"padding"!==n&&(s+=Z.css(e,"border"+Ce[o]+"Width",!0,i)));return s}function E(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=ze(e),s="border-box"===Z.css(e,"boxSizing",!1,o);if(i<=0||null==i){if(((i=w(e,t,o))<0||null==i)&&(i=e.style[t]),_e.test(i))return i;r=s&&(Q.boxSizingReliable()||i===e.style[t]),i=parseFloat(i)||0}return i+k(e,t,n||(s?"border":"content"),r,o)+"px"}function S(e,t){for(var n,r,i,o=[],s=0,a=e.length;sT.cacheLength&&delete n[r.shift()],n[e+" "]=t}var r=[];return n}function u(e){return e[W]=!0,e}function r(e){var t=q.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function t(e,t){for(var n=e.split("|"),r=e.length;r--;)T.attrHandle[n[r]]=t}function l(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||V)-(~e.sourceIndex||V);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function i(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function o(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function s(s){return u(function(o){return o=+o,u(function(e,t){for(var n,r=s([],e.length,o),i=r.length;i--;)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function g(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function a(){}function m(e){for(var t=0,n=e.length,r="";t+~]|"+ne+")"+ne+"*"),fe=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),pe=new RegExp(se),de=new RegExp("^"+ie+"$"),he={ID:new RegExp("^#("+re+")"),CLASS:new RegExp("^\\.("+re+")"),TAG:new RegExp("^("+re.replace("w","w*")+")"),ATTR:new RegExp("^"+oe),PSEUDO:new RegExp("^"+se),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},ge=/^(?:input|select|textarea|button)$/i,me=/^h\d$/i,ye=/^[^{]+\{\s*\[native \w/,ve=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,xe=/[+~]/,be=/'|\\/g,we=new RegExp("\\\\([\\da-f]{1,6}"+ne+"?|("+ne+")|.)","ig"),Te=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},Ce=function(){L()};try{K.apply(G=Z.call($.childNodes),$.childNodes),G[$.childNodes.length].nodeType}catch(Ne){K={apply:G.length?function(e,t){J.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}for(h in y=b.support={},N=b.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},L=b.setDocument=function(e){var t,n,u=e?e.ownerDocument||e:$;return u!==q&&9===u.nodeType&&u.documentElement?(H=(q=u).documentElement,(n=u.defaultView)&&n!==n.top&&(n.addEventListener?n.addEventListener("unload",Ce,!1):n.attachEvent&&n.attachEvent("onunload",Ce)),O=!N(u),y.attributes=r(function(e){return e.className="i",!e.getAttribute("className")}),y.getElementsByTagName=r(function(e){return e.appendChild(u.createComment("")),!e.getElementsByTagName("*").length}),y.getElementsByClassName=ye.test(u.getElementsByClassName),y.getById=r(function(e){return H.appendChild(e).id=W,!u.getElementsByName||!u.getElementsByName(W).length}),y.getById?(T.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&O){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},T.filter.ID=function(e){var t=e.replace(we,Te);return function(e){return e.getAttribute("id")===t}}):(delete T.find.ID,T.filter.ID=function(e){var n=e.replace(we,Te);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}}),T.find.TAG=y.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):y.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"!==e)return o;for(;n=o[i++];)1===n.nodeType&&r.push(n);return r},T.find.CLASS=y.getElementsByClassName&&function(e,t){if(O)return t.getElementsByClassName(e)},P=[],F=[],(y.qsa=ye.test(u.querySelectorAll))&&(r(function(e){H.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&F.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||F.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+W+"-]").length||F.push("~="),e.querySelectorAll(":checked").length||F.push(":checked"),e.querySelectorAll("a#"+W+"+*").length||F.push(".#.+[+~]")}),r(function(e){var t=u.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&F.push("name"+ne+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||F.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),F.push(",.*:")})),(y.matchesSelector=ye.test(R=H.matches||H.webkitMatchesSelector||H.mozMatchesSelector||H.oMatchesSelector||H.msMatchesSelector))&&r(function(e){y.disconnectedMatch=R.call(e,"div"),R.call(e,"[s!='']:x"),P.push("!=",se)}),F=F.length&&new RegExp(F.join("|")),P=P.length&&new RegExp(P.join("|")),t=ye.test(H.compareDocumentPosition),M=t||ye.test(H.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},U=t?function(e,t){if(e===t)return A=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!y.sortDetached&&t.compareDocumentPosition(e)===n?e===u||e.ownerDocument===$&&M($,e)?-1:t===u||t.ownerDocument===$&&M($,t)?1:j?ee(j,e)-ee(j,t):0:4&n?-1:1)}:function(e,t){if(e===t)return A=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],a=[t];if(!i||!o)return e===u?-1:t===u?1:i?-1:o?1:j?ee(j,e)-ee(j,t):0;if(i===o)return l(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)a.unshift(n);for(;s[r]===a[r];)r++;return r?l(s[r],a[r]):s[r]===$?-1:a[r]===$?1:0},u):q},b.matches=function(e,t){return b(e,null,null,t)},b.matchesSelector=function(e,t){if((e.ownerDocument||e)!==q&&L(e),t=t.replace(fe,"='$1']"),y.matchesSelector&&O&&(!P||!P.test(t))&&(!F||!F.test(t)))try{var n=R.call(e,t);if(n||y.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(Ne){}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(we,Te),e[3]=(e[3]||e[4]||e[5]||"").replace(we,Te),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||b.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&b.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return he.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&pe.test(n)&&(t=k(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(we,Te).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=_[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&_(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=b.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1(?:<\/\1>|)$/,ae=/^.[^:#\[\.,]*$/;Z.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?Z.find.matchesSelector(r,e)?[r]:[]:Z.find.matches(e,Z.grep(t,function(e){return 1===e.nodeType}))},Z.fn.extend({find:function(e){var t,n=this.length,r=[],i=this;if("string"!=typeof e)return this.pushStack(Z(e).filter(function(){for(t=0;t)[^>]*|#([\w-]*))$/;(Z.fn.init=function(e,t){var n,r;if(!e)return this;if("string"!=typeof e)return e.nodeType?(this.context=this[0]=e,this.length=1,this):Z.isFunction(e)?"undefined"!=typeof ue.ready?ue.ready(e):e(Z):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),Z.makeArray(e,this));if(!( +n="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:le.exec(e))||!n[1]&&t)return!t||t.jquery?(t||ue).find(e):this.constructor(t).find(e);if(n[1]){if(t=t instanceof Z?t[0]:t,Z.merge(this,Z.parseHTML(n[1],t&&t.nodeType?t.ownerDocument||t:J,!0)),se.test(n[1])&&Z.isPlainObject(t))for(n in t)Z.isFunction(this[n])?this[n](t[n]):this.attr(n,t[n]);return this}return(r=J.getElementById(n[2]))&&r.parentNode&&(this.length=1,this[0]=r),this.context=J,this.selector=e,this}).prototype=Z.fn,ue=Z(J);var ce=/^(?:parents|prev(?:Until|All))/,fe={children:!0,contents:!0,next:!0,prev:!0};Z.extend({dir:function(e,t,n){for(var r=[],i=n!==undefined;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&Z(e).is(n))break;r.push(e)}return r},sibling:function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}}),Z.fn.extend({has:function(e){var t=Z(e,this),n=t.length;return this.filter(function(){for(var e=0;ex",Q.noCloneChecked=!!be.cloneNode(!0).lastChild.defaultValue;var Ee=typeof undefined;Q.focusinBubbles="onfocusin"in h;var Se=/^key/,De=/^(?:mouse|pointer|contextmenu)|click/,je=/^(?:focusinfocus|focusoutblur)$/,Ae=/^([^.]*)(?:\.(.+)|)$/;Z.event={global:{},add:function(t,e,n,r,i){var o,s,a,u,l,c,f,p,d,h,g,m=me.get(t);if(m)for(n.handler&&(n=(o=n).handler,i=o.selector),n.guid||(n.guid=Z.guid++),(u=m.events)||(u=m.events={}),(s=m.handle)||(s=m.handle=function(e){return typeof Z!==Ee&&Z.event.triggered!==e.type?Z.event.dispatch.apply(t,arguments):undefined}),l=(e=(e||"").match(de)||[""]).length;l--;)d=g=(a=Ae.exec(e[l])||[])[1],h=(a[2]||"").split(".").sort(),d&&(f=Z.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=Z.event.special[d]||{},c=Z.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&Z.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,s)||t.addEventListener&&t.addEventListener(d,s,!1)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),Z.event.global[d]=!0)},remove:function(e,t,n,r,i){var o,s,a,u,l,c,f,p,d,h,g,m=me.hasData(e)&&me.get(e);if(m&&(u=m.events)){for(l=(t=(t||"").match(de)||[""]).length;l--;)if(d=g=(a=Ae.exec(t[l])||[])[1],h=(a[2]||"").split(".").sort(),d){for(f=Z.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],a=a[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=p.length;o--;)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));s&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,m.handle)||Z.removeEvent(e,d,m.handle),delete u[d])}else for(d in u)Z.event.remove(e,d+t[l],n,r,!0);Z.isEmptyObject(u)&&(delete m.handle,me.remove(e,"events"))}},trigger:function(e,t,n,r){var i,o,s,a,u,l,c,f=[n||J],p=G.call(e,"type")?e.type:e,d=G.call(e,"namespace")?e.namespace.split("."):[];if(o=s=n=n||J,3!==n.nodeType&&8!==n.nodeType&&!je.test(p+Z.event.triggered)&&(0<=p.indexOf(".")&&(p=(d=p.split(".")).shift(),d.sort()),u=p.indexOf(":")<0&&"on"+p,(e=e[Z.expando]?e:new Z.Event(p,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=d.join("."),e.namespace_re=e.namespace?new RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=undefined,e.target||(e.target=n),t=null==t?[e]:Z.makeArray(t,[e]),c=Z.event.special[p]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!Z.isWindow(n)){for(a=c.delegateType||p,je.test(a+p)||(o=o.parentNode);o;o=o.parentNode)f.push(o),s=o;s===(n.ownerDocument||J)&&f.push(s.defaultView||s.parentWindow||h)}for(i=0;(o=f[i++])&&!e.isPropagationStopped();)e.type=1]*)\/>/gi,qe=/<([\w:]+)/,He=/<|&#?\w+;/,Oe=/<(?:script|style|link)/i,Fe=/checked\s*(?:[^=]|=\s*.checked.)/i,Pe=/^$|\/(?:java|ecma)script/i,Re=/^true\/(.*)/,Me=/^\s*\s*$/g,We={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};We.optgroup=We.option,We.tbody=We.tfoot=We.colgroup=We.caption=We.thead,We.th=We.td,Z.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=Z.contains(e.ownerDocument,e);if(!(Q.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||Z.isXMLDoc(e)))for(s=v(a),r=0,i=(o=v(e)).length;r")+a[2],l=a[0];l--;)o=o.lastChild;Z.merge(f,o.childNodes),(o=c.firstChild).textContent=""}else f.push(t.createTextNode(i));for(c.textContent="",p=0;i=f[p++];)if((!r||-1===Z.inArray(i,r))&&(u=Z.contains(i.ownerDocument,i),o=v(c.appendChild(i),"script"),u&&y(o),n))for(l=0;i=o[l++];)Pe.test(i.type||"")&&n.push(i);return c},cleanData:function(e){for(var t,n,r,i,o=Z.event.special,s=0;(n=e[s])!==undefined;s++){if(Z.acceptData(n)&&(i=n[me.expando])&&(t=me.cache[i])){if(t.events)for(r in t.events)o[r]?Z.event.remove(n,r):Z.removeEvent(n,r,t.handle);me.cache[i]&&delete me.cache[i]}delete ye.cache[n[ye.expando]]}}}),Z.fn.extend({text:function(e){return ge(this,function(e){return e===undefined?Z.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||c(this,e).appendChild(e)})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=c(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){for(var n,r=e?Z.filter(e,this):this,i=0;null!=(n=r[i]);i++)t||1!==n.nodeType||Z.cleanData(v(n)),n.parentNode&&(t&&Z.contains(n.ownerDocument,n)&&y(v(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(Z.cleanData(v(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return Z.clone(this,e,t)})},html:function(e){return ge(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Oe.test(e)&&!We[(qe.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(Le,"<$1>");try{for(;n").prop({async:!0,charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),J.head.appendChild(r[0])},abort:function(){i&&i()}}});var Pt=[],Rt=/(=)\?(?=&|$)|\?\?/;Z.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Pt.pop()||Z.expando+"_"+dt++;return this[e]=!0,e}}),Z.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,s=!1!==e.jsonp&&(Rt.test(e.url)?"url":"string"==typeof e.data&&!(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Rt.test(e.data)&&"data");if(s||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=Z.isFunction(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,s?e[s]=e[s].replace(Rt,"$1"+r):!1!==e.jsonp&&(e.url+=(ht.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||Z.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=h[r],h[r]=function(){o=arguments},n.always(function(){h[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Pt.push(r)),o&&Z.isFunction(i)&&i(o[0]),o=i=undefined}),"script"}),Z.parseHTML=function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||J;var r=se.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=Z.buildFragment([e],t,i),i&&i.length&&Z(i).remove(),Z.merge([],r.childNodes))};var Mt=Z.fn.load;Z.fn.load=function(e,t,n){if("string"!=typeof e&&Mt)return Mt.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return 0<=a&&(r=Z.trim(e.slice(a)),e=e.slice(0,a)),Z.isFunction(t)?(n=t,t=undefined):t&&"object"==typeof t&&(i="POST"),0").append(Z.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},Z.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){Z.fn[t]=function(e){return this.on(t,e)}}),Z.expr.filters.animated=function(t){return Z.grep(Z.timers,function(e){return t===e.elem}).length};var Wt=h.document.documentElement;Z.offset={setOffset:function(e,t,n){var r,i,o,s,a,u,l=Z.css(e,"position"),c=Z(e),f={};"static"===l&&(e.style.position="relative"),a=c.offset(),o=Z.css(e,"top"),u=Z.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(s=(r=c.position()).top,i=r.left):(s=parseFloat(o)||0,i=parseFloat(u)||0),Z.isFunction(t)&&(t=t.call(e,n,a)),null!=t.top&&(f.top=t.top-a.top+s),null!=t.left&&(f.left=t.left-a.left+i),"using"in t?t.using.call(e,f):c.css(f)}},Z.fn.extend({offset:function(t){if(arguments.length)return t===undefined?this:this.each(function(e){Z.offset.setOffset(this,t,e)});var e,n,r=this[0],i={top:0,left:0},o=r&&r.ownerDocument;return o?(e=o.documentElement,Z.contains(e,r)?(typeof r.getBoundingClientRect!==Ee&&(i=r.getBoundingClientRect()),n=I(o),{top:i.top+n.pageYOffset-e.clientTop,left:i.left+n.pageXOffset-e.clientLeft}):i):void 0},position:function(){if(this[0]){var e,t,n=this[0],r={top:0,left:0};return"fixed"===Z.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),Z.nodeName(e[0],"html")||(r=e.offset()),r.top+=Z.css(e[0],"borderTopWidth",!0),r.left+=Z.css(e[0],"borderLeftWidth",!0)),{top:t.top-r.top-Z.css(n,"marginTop",!0),left:t.left-r.left-Z.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent||Wt;e&&!Z.nodeName(e,"html")&&"static"===Z.css(e,"position");)e=e.offsetParent;return e||Wt})}}),Z.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;Z.fn[t]=function(e){return ge(this,function(e,t,n){var r=I(e);if(n===undefined)return r?r[i]:e[t];r?r.scrollTo(o?h.pageXOffset:n,o?n:h.pageYOffset):e[t]=n},t,e,arguments.length,null)}}),Z.each(["top","left"],function(e,n){Z.cssHooks[n]=T(Q.pixelPosition,function(e,t){if(t)return t=w(e,n),_e.test(t)?Z(e).position()[n]+"px":t})}),Z.each({Height:"height",Width:"width"},function(o,s){Z.each({padding:"inner"+o,content:s,"":"outer"+o},function(r,e){Z.fn[e]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return ge(this,function(e,t,n){var r;return Z.isWindow(e)?e.document.documentElement["client"+o]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+o],r["scroll"+o],e.body["offset"+o],r["offset"+o],r["client"+o])):n===undefined?Z.css(e,t,i):Z.style(e,t,n,i)},s,n?e:undefined,n,null)}})}),Z.fn.size=function(){return this.length},Z.fn.andSelf=Z.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return Z});var $t=h.jQuery,It=h.$;return Z.noConflict=function(e){return h.$===Z&&(h.$=It),e&&h.jQuery===Z&&(h.jQuery=$t),Z},typeof e===Ee&&(h.jQuery=h.$=Z),Z}); \ No newline at end of file diff --git a/assets/jquery-aa71a7b50270602be524223735204e4e.js.gz b/assets/jquery-aa71a7b50270602be524223735204e4e.js.gz new file mode 100644 index 0000000000..0a02267995 Binary files /dev/null and b/assets/jquery-aa71a7b50270602be524223735204e4e.js.gz differ diff --git a/assets/jquery.cookie-600df63e64417ec0c172cd3580ffe4f3.js b/assets/jquery.cookie-600df63e64417ec0c172cd3580ffe4f3.js new file mode 100644 index 0000000000..510ee063cc --- /dev/null +++ b/assets/jquery.cookie-600df63e64417ec0c172cd3580ffe4f3.js @@ -0,0 +1 @@ +!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof exports?e(require("jquery")):e(jQuery)}(function(s){function m(e){return j.raw?e:encodeURIComponent(e)}function x(e){return j.raw?e:decodeURIComponent(e)}function k(e){return m(j.json?JSON.stringify(e):String(e))}function o(e){0===e.indexOf('"')&&(e=e.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return e=decodeURIComponent(e.replace(i," ")),j.json?JSON.parse(e):e}catch(n){}}function l(e,n){var i=j.raw?e:o(e);return s.isFunction(n)?n(i):i}var i=/\+/g,j=s.cookie=function(e,n,i){if(n!==undefined&&!s.isFunction(n)){if("number"==typeof(i=s.extend({},j.defaults,i)).expires){var o=i.expires,r=i.expires=new Date;r.setTime(+r+864e5*o)}return document.cookie=[m(e),"=",k(n),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var t=e?undefined:{},u=document.cookie?document.cookie.split("; "):[],c=0,f=u.length;c")).appendTo(t.documentElement))[0].contentDocument).write(),t.close(),n=x(e,t),$e.detach()),Ie[e]=n),n}function w(e,t,n){var r,i,o,s,a=e.style;return(n=n||ze(e))&&(s=n.getPropertyValue(t)||n[t]),n&&(""!==s||Z.contains(e.ownerDocument,e)||(s=Z.style(e,t)),_e.test(s)&&Be.test(t)&&(r=a.width,i=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=s,s=n.width,a.width=r,a.minWidth=i,a.maxWidth=o)),void 0!==s?s+"":s}function T(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function C(e,t){if(t in e)return t;for(var n=t[0].toUpperCase()+t.slice(1),r=t,i=Qe.length;i--;)if((t=Qe[i]+n)in e)return t;return r}function N(e,t,n){var r=Ue.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function k(e,t,n,r,i){for(var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;o<4;o+=2)"margin"===n&&(s+=Z.css(e,n+Ce[o],!0,i)),r?("content"===n&&(s-=Z.css(e,"padding"+Ce[o],!0,i)),"margin"!==n&&(s-=Z.css(e,"border"+Ce[o]+"Width",!0,i))):(s+=Z.css(e,"padding"+Ce[o],!0,i),"padding"!==n&&(s+=Z.css(e,"border"+Ce[o]+"Width",!0,i)));return s}function E(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=ze(e),s="border-box"===Z.css(e,"boxSizing",!1,o);if(i<=0||null==i){if(((i=w(e,t,o))<0||null==i)&&(i=e.style[t]),_e.test(i))return i;r=s&&(Q.boxSizingReliable()||i===e.style[t]),i=parseFloat(i)||0}return i+k(e,t,n||(s?"border":"content"),r,o)+"px"}function S(e,t){for(var n,r,i,o=[],s=0,a=e.length;sT.cacheLength&&delete n[r.shift()],n[e+" "]=t}var r=[];return n}function u(e){return e[W]=!0,e}function r(e){var t=q.createElement("div");try{return!!e(t)}catch(v){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function t(e,t){for(var n=e.split("|"),r=e.length;r--;)T.attrHandle[n[r]]=t}function l(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||V)-(~e.sourceIndex||V);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function i(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function o(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function s(s){return u(function(o){return o=+o,u(function(e,t){for(var n,r=s([],e.length,o),i=r.length;i--;)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function h(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function a(){}function g(e){for(var t=0,n=e.length,r="";t+~]|"+ne+")"+ne+"*"),fe=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),pe=new RegExp(se),de=new RegExp("^"+ie+"$"),he={ID:new RegExp("^#("+re+")"),CLASS:new RegExp("^\\.("+re+")"),TAG:new RegExp("^("+re.replace("w","w*")+")"),ATTR:new RegExp("^"+oe),PSEUDO:new RegExp("^"+se),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},ge=/^(?:input|select|textarea|button)$/i,me=/^h\d$/i,ve=/^[^{]+\{\s*\[native \w/,ye=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,xe=/[+~]/,be=/'|\\/g,we=new RegExp("\\\\([\\da-f]{1,6}"+ne+"?|("+ne+")|.)","ig"),Te=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},Ce=function(){L()};try{K.apply(G=Z.call($.childNodes),$.childNodes),G[$.childNodes.length].nodeType}catch(Pe){K={apply:G.length?function(e,t){J.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}for(m in v=b.support={},N=b.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},L=b.setDocument=function(e){var t,n,u=e?e.ownerDocument||e:$;return u!==q&&9===u.nodeType&&u.documentElement?(H=(q=u).documentElement,(n=u.defaultView)&&n!==n.top&&(n.addEventListener?n.addEventListener("unload",Ce,!1):n.attachEvent&&n.attachEvent("onunload",Ce)),O=!N(u),v.attributes=r(function(e){return e.className="i",!e.getAttribute("className")}),v.getElementsByTagName=r(function(e){return e.appendChild(u.createComment("")),!e.getElementsByTagName("*").length}),v.getElementsByClassName=ve.test(u.getElementsByClassName),v.getById=r(function(e){return H.appendChild(e).id=W,!u.getElementsByName||!u.getElementsByName(W).length}),v.getById?(T.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&O){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},T.filter.ID=function(e){var t=e.replace(we,Te);return function(e){return e.getAttribute("id")===t}}):(delete T.find.ID,T.filter.ID=function(e){var n=e.replace(we,Te);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}}),T.find.TAG=v.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):v.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"!==e)return o;for(;n=o[i++];)1===n.nodeType&&r.push(n);return r},T.find.CLASS=v.getElementsByClassName&&function(e,t){return O?t.getElementsByClassName(e):void 0},P=[],F=[],(v.qsa=ve.test(u.querySelectorAll))&&(r(function(e){H.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&F.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||F.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+W+"-]").length||F.push("~="),e.querySelectorAll(":checked").length||F.push(":checked"),e.querySelectorAll("a#"+W+"+*").length||F.push(".#.+[+~]")}),r(function(e){var t=u.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&F.push("name"+ne+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||F.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),F.push(",.*:")})),(v.matchesSelector=ve.test(R=H.matches||H.webkitMatchesSelector||H.mozMatchesSelector||H.oMatchesSelector||H.msMatchesSelector))&&r(function(e){v.disconnectedMatch=R.call(e,"div"),R.call(e,"[s!='']:x"),P.push("!=",se)}),F=F.length&&new RegExp(F.join("|")),P=P.length&&new RegExp(P.join("|")),t=ve.test(H.compareDocumentPosition),M=t||ve.test(H.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},U=t?function(e,t){if(e===t)return A=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!v.sortDetached&&t.compareDocumentPosition(e)===n?e===u||e.ownerDocument===$&&M($,e)?-1:t===u||t.ownerDocument===$&&M($,t)?1:j?ee(j,e)-ee(j,t):0:4&n?-1:1)}:function(e,t){if(e===t)return A=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],a=[t];if(!i||!o)return e===u?-1:t===u?1:i?-1:o?1:j?ee(j,e)-ee(j,t):0;if(i===o)return l(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)a.unshift(n);for(;s[r]===a[r];)r++;return r?l(s[r],a[r]):s[r]===$?-1:a[r]===$?1:0},u):q},b.matches=function(e,t){return b(e,null,null,t)},b.matchesSelector=function(e,t){if((e.ownerDocument||e)!==q&&L(e),t=t.replace(fe,"='$1']"),!(!v.matchesSelector||!O||P&&P.test(t)||F&&F.test(t)))try{var n=R.call(e,t);if(n||v.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(C){}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(we,Te),e[3]=(e[3]||e[4]||e[5]||"").replace(we,Te),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||b.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&b.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return he.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&pe.test(n)&&(t=k(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(we,Te).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=_[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&_(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=b.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1(?:<\/\1>|)$/,ae=/^.[^:#\[\.,]*$/;Z.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?Z.find.matchesSelector(r,e)?[r]:[]:Z.find.matches(e,Z.grep(t,function(e){return 1===e.nodeType}))},Z.fn.extend({find:function(e){var t,n=this.length,r=[],i=this;if("string"!=typeof e)return this.pushStack(Z(e).filter(function(){for(t=0;t)[^>]*|#([\w-]*))$/;(Z.fn.init=function(e,t){var n,r;if(!e)return this;if("string"!=typeof e)return e.nodeType?(this.context=this[0]=e,this.length=1,this):Z.isFunction(e)?"undefined"!=typeof ue.ready?ue.ready(e):e(Z):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),Z.makeArray(e,this));if(!(n="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[ +null,e,null]:le.exec(e))||!n[1]&&t)return!t||t.jquery?(t||ue).find(e):this.constructor(t).find(e);if(n[1]){if(t=t instanceof Z?t[0]:t,Z.merge(this,Z.parseHTML(n[1],t&&t.nodeType?t.ownerDocument||t:J,!0)),se.test(n[1])&&Z.isPlainObject(t))for(n in t)Z.isFunction(this[n])?this[n](t[n]):this.attr(n,t[n]);return this}return(r=J.getElementById(n[2]))&&r.parentNode&&(this.length=1,this[0]=r),this.context=J,this.selector=e,this}).prototype=Z.fn,ue=Z(J);var ce=/^(?:parents|prev(?:Until|All))/,fe={children:!0,contents:!0,next:!0,prev:!0};Z.extend({dir:function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&Z(e).is(n))break;r.push(e)}return r},sibling:function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}}),Z.fn.extend({has:function(e){var t=Z(e,this),n=t.length;return this.filter(function(){for(var e=0;ex",Q.noCloneChecked=!!be.cloneNode(!0).lastChild.defaultValue;var Ee="undefined";Q.focusinBubbles="onfocusin"in h;var Se=/^key/,De=/^(?:mouse|pointer|contextmenu)|click/,je=/^(?:focusinfocus|focusoutblur)$/,Ae=/^([^.]*)(?:\.(.+)|)$/;Z.event={global:{},add:function(t,e,n,r,i){var o,s,a,u,l,c,f,p,d,h,g,m=me.get(t);if(m)for(n.handler&&(n=(o=n).handler,i=o.selector),n.guid||(n.guid=Z.guid++),(u=m.events)||(u=m.events={}),(s=m.handle)||(s=m.handle=function(e){return typeof Z!==Ee&&Z.event.triggered!==e.type?Z.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(de)||[""]).length;l--;)d=g=(a=Ae.exec(e[l])||[])[1],h=(a[2]||"").split(".").sort(),d&&(f=Z.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=Z.event.special[d]||{},c=Z.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&Z.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,s)||t.addEventListener&&t.addEventListener(d,s,!1)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),Z.event.global[d]=!0)},remove:function(e,t,n,r,i){var o,s,a,u,l,c,f,p,d,h,g,m=me.hasData(e)&&me.get(e);if(m&&(u=m.events)){for(l=(t=(t||"").match(de)||[""]).length;l--;)if(d=g=(a=Ae.exec(t[l])||[])[1],h=(a[2]||"").split(".").sort(),d){for(f=Z.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],a=a[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=p.length;o--;)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));s&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,m.handle)||Z.removeEvent(e,d,m.handle),delete u[d])}else for(d in u)Z.event.remove(e,d+t[l],n,r,!0);Z.isEmptyObject(u)&&(delete m.handle,me.remove(e,"events"))}},trigger:function(e,t,n,r){var i,o,s,a,u,l,c,f=[n||J],p=G.call(e,"type")?e.type:e,d=G.call(e,"namespace")?e.namespace.split("."):[];if(o=s=n=n||J,3!==n.nodeType&&8!==n.nodeType&&!je.test(p+Z.event.triggered)&&(0<=p.indexOf(".")&&(p=(d=p.split(".")).shift(),d.sort()),u=p.indexOf(":")<0&&"on"+p,(e=e[Z.expando]?e:new Z.Event(p,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=d.join("."),e.namespace_re=e.namespace?new RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:Z.makeArray(t,[e]),c=Z.event.special[p]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!Z.isWindow(n)){for(a=c.delegateType||p,je.test(a+p)||(o=o.parentNode);o;o=o.parentNode)f.push(o),s=o;s===(n.ownerDocument||J)&&f.push(s.defaultView||s.parentWindow||h)}for(i=0;(o=f[i++])&&!e.isPropagationStopped();)e.type=1]*)\/>/gi,qe=/<([\w:]+)/,He=/<|&#?\w+;/,Oe=/<(?:script|style|link)/i,Fe=/checked\s*(?:[^=]|=\s*.checked.)/i,Pe=/^$|\/(?:java|ecma)script/i,Re=/^true\/(.*)/,Me=/^\s*\s*$/g,We={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};We.optgroup=We.option,We.tbody=We.tfoot=We.colgroup=We.caption=We.thead,We.th=We.td,Z.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=Z.contains(e.ownerDocument,e);if(!(Q.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||Z.isXMLDoc(e)))for(s=y(a),r=0,i=(o=y(e)).length;r")+a[2],l=a[0];l--;)o=o.lastChild;Z.merge(f,o.childNodes),(o=c.firstChild).textContent=""}else f.push(t.createTextNode(i));for(c.textContent="",p=0;i=f[p++];)if((!r||-1===Z.inArray(i,r))&&(u=Z.contains(i.ownerDocument,i),o=y(c.appendChild(i),"script"),u&&v(o),n))for(l=0;i=o[l++];)Pe.test(i.type||"")&&n.push(i);return c},cleanData:function(e){for(var t,n,r,i,o=Z.event.special,s=0;void 0!==(n=e[s]);s++){if(Z.acceptData(n)&&((i=n[me.expando])&&(t=me.cache[i]))){if(t.events)for(r in t.events)o[r]?Z.event.remove(n,r):Z.removeEvent(n,r,t.handle);me.cache[i]&&delete me.cache[i]}delete ve.cache[n[ve.expando]]}}}),Z.fn.extend({text:function(e){return ge(this,function(e){return void 0===e?Z.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=e)})},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||c(this,e).appendChild(e)})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=c(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){for(var n,r=e?Z.filter(e,this):this,i=0;null!=(n=r[i]);i++)t||1!==n.nodeType||Z.cleanData(y(n)),n.parentNode&&(t&&Z.contains(n.ownerDocument,n)&&v(y(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(Z.cleanData(y(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return Z.clone(this,e,t)})},html:function(e){return ge(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Oe.test(e)&&!We[(qe.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(Le,"<$1>");try{for(;n").prop({async:!0,charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),J.head.appendChild(r[0])},abort:function(){i&&i()}}});var Pt=[],Rt=/(=)\?(?=&|$)|\?\?/;Z.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Pt.pop()||Z.expando+"_"+dt++;return this[e]=!0,e}}),Z.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,s=!1!==e.jsonp&&(Rt.test(e.url)?"url":"string"==typeof e.data&&!(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Rt.test(e.data)&&"data");return s||"jsonp"===e.dataTypes[0]?(r=e.jsonpCallback=Z.isFunction(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,s?e[s]=e[s].replace(Rt,"$1"+r):!1!==e.jsonp&&(e.url+=(ht.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||Z.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=h[r],h[r]=function(){o=arguments},n.always(function(){h[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Pt.push(r)),o&&Z.isFunction(i)&&i(o[0]),o=i=void 0}),"script"):void 0}),Z.parseHTML=function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||J;var r=se.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=Z.buildFragment([e],t,i),i&&i.length&&Z(i).remove(),Z.merge([],r.childNodes))};var Mt=Z.fn.load;Z.fn.load=function(e,t,n){if("string"!=typeof e&&Mt)return Mt.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return 0<=a&&(r=Z.trim(e.slice(a)),e=e.slice(0,a)),Z.isFunction(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0").append(Z.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},Z.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){Z.fn[t]=function(e){return this.on(t,e)}}),Z.expr.filters.animated=function(t){return Z.grep(Z.timers,function(e){return t===e.elem}).length};var Wt=h.document.documentElement;Z.offset={setOffset:function(e,t,n){var r,i,o,s,a,u,l=Z.css(e,"position"),c=Z(e),f={};"static"===l&&(e.style.position="relative"),a=c.offset(),o=Z.css(e,"top"),u=Z.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(s=(r=c.position()).top,i=r.left):(s=parseFloat(o)||0,i=parseFloat(u)||0),Z.isFunction(t)&&(t=t.call(e,n,a)),null!=t.top&&(f.top=t.top-a.top+s),null!=t.left&&(f.left=t.left-a.left+i),"using"in t?t.using.call(e,f):c.css(f)}},Z.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){Z.offset.setOffset(this,t,e)});var e,n,r=this[0],i={top:0,left:0},o=r&&r.ownerDocument;return o?(e=o.documentElement,Z.contains(e,r)?(typeof r.getBoundingClientRect!==Ee&&(i=r.getBoundingClientRect()),n=I(o),{top:i.top+n.pageYOffset-e.clientTop,left:i.left+n.pageXOffset-e.clientLeft}):i):void 0},position:function(){if(this[0]){var e,t,n=this[0],r={top:0,left:0};return"fixed"===Z.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),Z.nodeName(e[0],"html")||(r=e.offset()),r.top+=Z.css(e[0],"borderTopWidth",!0),r.left+=Z.css(e[0],"borderLeftWidth",!0)),{top:t.top-r.top-Z.css(n,"marginTop",!0),left:t.left-r.left-Z.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent||Wt;e&&!Z.nodeName(e,"html")&&"static"===Z.css(e,"position");)e=e.offsetParent;return e||Wt})}}),Z.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;Z.fn[t]=function(e){return ge(this,function(e,t,n){var r=I(e);return void 0===n?r?r[i]:e[t]:void(r?r.scrollTo(o?h.pageXOffset:n,o?n:h.pageYOffset):e[t]=n)},t,e,arguments.length,null)}}),Z.each(["top","left"],function(e,n){Z.cssHooks[n]=T(Q.pixelPosition,function(e,t){return t?(t=w(e,n),_e.test(t)?Z(e).position()[n]+"px":t):void 0})}),Z.each({Height:"height",Width:"width"},function(o,s){Z.each({padding:"inner"+o,content:s,"":"outer"+o},function(r,e){Z.fn[e]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return ge(this,function(e,t,n){var r;return Z.isWindow(e)?e.document.documentElement["client"+o]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+o],r["scroll"+o],e.body["offset"+o],r["offset"+o],r["client"+o])):void 0===n?Z.css(e,t,i):Z.style(e,t,n,i)},s,n?e:void 0,n,null)}})}),Z.fn.size=function(){return this.length},Z.fn.andSelf=Z.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return Z});var $t=h.jQuery,It=h.$;return Z.noConflict=function(e){return h.$===Z&&(h.$=It),e&&h.jQuery===Z&&(h.jQuery=$t),Z},typeof e===Ee&&(h.jQuery=h.$=Z),Z}); \ No newline at end of file diff --git a/assets/jquery.min-92bca385e77eff06fdfc99d71ff5d9cb.js.gz b/assets/jquery.min-92bca385e77eff06fdfc99d71ff5d9cb.js.gz new file mode 100644 index 0000000000..d28a33383b Binary files /dev/null and b/assets/jquery.min-92bca385e77eff06fdfc99d71ff5d9cb.js.gz differ diff --git a/assets/prism-193ebecb65a347c425ecdb3c4592fd0e.js b/assets/prism-193ebecb65a347c425ecdb3c4592fd0e.js new file mode 100644 index 0000000000..df6353fa7f --- /dev/null +++ b/assets/prism-193ebecb65a347c425ecdb3c4592fd0e.js @@ -0,0 +1,8 @@ +var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var l=/\blang(?:uage)?-(\w+)\b/i,t=0,P=_self.Prism={util:{encode:function(e){return e instanceof s?new s(e.type,P.util.encode(e.content),e.alias):"Array"===P.util.type(e)?e.map(P.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(h instanceof n)){l.lastIndex=0;var S=1;if(!(k=l.exec(h))&&p&&b!=a.length-1){if(l.lastIndex=f,!(k=l.exec(e)))break;for(var E=k.index+(c?k[1].length:0),y=k.index+k[0].length,v=b,A=f,T=a.length;v"+a.content+""},!_self.document)return _self.addEventListener&&_self.addEventListener("message",function(e){var t=JSON.parse(e.data),n=t.language,a=t.code,i=t.immediateClose;_self.postMessage(P.highlight(a,P.languages[n],n)),i&&_self.close()},!1),_self.Prism;var e=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return e&&(P.filename=e.src,document.addEventListener&&!e.hasAttribute("data-manual")&&("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(P.highlightAll):window.setTimeout(P.highlightAll,16):document.addEventListener("DOMContentLoaded",P.highlightAll))),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism),Prism.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/()[\w\W]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag)),Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/},Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*\*?|\/|~|\^|%|\.{3}/}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0}}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\\\|\\?[^\\])*?`/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript"}}),Prism.languages.js=Prism.languages.javascript,Prism.languages.abap={comment:/^\*.*/m,string:/(`|')(\\?.)*?\1/m,"string-template":{pattern:/(\||\})(\\?.)*?(?=\||\{)/,lookbehind:!0,alias:"string"},"eol-comment":{pattern:/(^|\s)".*/m,lookbehind:!0,alias:"comment"},keyword:{pattern:/(\s|\.|^)(?:SCIENTIFIC_WITH_LEADING_ZERO|SCALE_PRESERVING_SCIENTIFIC|RMC_COMMUNICATION_FAILURE|END-ENHANCEMENT-SECTION|MULTIPLY-CORRESPONDING|SUBTRACT-CORRESPONDING|VERIFICATION-MESSAGE|DIVIDE-CORRESPONDING|ENHANCEMENT-SECTION|CURRENCY_CONVERSION|RMC_SYSTEM_FAILURE|START-OF-SELECTION|MOVE-CORRESPONDING|RMC_INVALID_STATUS|CUSTOMER-FUNCTION|END-OF-DEFINITION|ENHANCEMENT-POINT|SYSTEM-EXCEPTIONS|ADD-CORRESPONDING|SCALE_PRESERVING|SELECTION-SCREEN|CURSOR-SELECTION|END-OF-SELECTION|LOAD-OF-PROGRAM|SCROLL-BOUNDARY|SELECTION-TABLE|EXCEPTION-TABLE|IMPLEMENTATIONS|PARAMETER-TABLE|RIGHT-JUSTIFIED|UNIT_CONVERSION|AUTHORITY-CHECK|LIST-PROCESSING|SIGN_AS_POSTFIX|COL_BACKGROUND|IMPLEMENTATION|INTERFACE-POOL|TRANSFORMATION|IDENTIFICATION|ENDENHANCEMENT|LINE-SELECTION|INITIALIZATION|LEFT-JUSTIFIED|SELECT-OPTIONS|SELECTION-SETS|COMMUNICATION|CORRESPONDING|DECIMAL_SHIFT|PRINT-CONTROL|VALUE-REQUEST|CHAIN-REQUEST|FUNCTION-POOL|FIELD-SYMBOLS|FUNCTIONALITY|INVERTED-DATE|SELECTION-SET|CLASS-METHODS|OUTPUT-LENGTH|CLASS-CODING|COL_NEGATIVE|ERRORMESSAGE|FIELD-GROUPS|HELP-REQUEST|NO-EXTENSION|NO-TOPOFPAGE|REDEFINITION|DISPLAY-MODE|ENDINTERFACE|EXIT-COMMAND|FIELD-SYMBOL|NO-SCROLLING|SHORTDUMP-ID|ACCESSPOLICY|CLASS-EVENTS|COL_POSITIVE|DECLARATIONS|ENHANCEMENTS|FILTER-TABLE|SWITCHSTATES|SYNTAX-CHECK|TRANSPORTING|ASYNCHRONOUS|SYNTAX-TRACE|TOKENIZATION|USER-COMMAND|WITH-HEADING|ABAP-SOURCE|BREAK-POINT|CHAIN-INPUT|COMPRESSION|FIXED-POINT|NEW-SECTION|NON-UNICODE|OCCURRENCES|RESPONSIBLE|SYSTEM-CALL|TRACE-TABLE|ABBREVIATED|CHAR-TO-HEX|END-OF-FILE|ENDFUNCTION|ENVIRONMENT|ASSOCIATION|COL_HEADING|EDITOR-CALL|END-OF-PAGE|ENGINEERING|IMPLEMENTED|INTENSIFIED|RADIOBUTTON|SYSTEM-EXIT|TOP-OF-PAGE|TRANSACTION|APPLICATION|CONCATENATE|DESTINATION|ENHANCEMENT|IMMEDIATELY|NO-GROUPING|PRECOMPILED|REPLACEMENT|TITLE-LINES|ACTIVATION|BYTE-ORDER|CLASS-POOL|CONNECTION|CONVERSION|DEFINITION|DEPARTMENT|EXPIRATION|INHERITING|MESSAGE-ID|NO-HEADING|PERFORMING|QUEUE-ONLY|RIGHTSPACE|SCIENTIFIC|STATUSINFO|STRUCTURES|SYNCPOINTS|WITH-TITLE|ATTRIBUTES|BOUNDARIES|CLASS-DATA|COL_NORMAL|DD\/MM\/YYYY|DESCENDING|INTERFACES|LINE-COUNT|MM\/DD\/YYYY|NON-UNIQUE|PRESERVING|SELECTIONS|STATEMENTS|SUBROUTINE|TRUNCATION|TYPE-POOLS|ARITHMETIC|BACKGROUND|ENDPROVIDE|EXCEPTIONS|IDENTIFIER|INDEX-LINE|OBLIGATORY|PARAMETERS|PERCENTAGE|PUSHBUTTON|RESOLUTION|COMPONENTS|DEALLOCATE|DISCONNECT|DUPLICATES|FIRST-LINE|HEAD-LINES|NO-DISPLAY|OCCURRENCE|RESPECTING|RETURNCODE|SUBMATCHES|TRACE-FILE|ASCENDING|BYPASSING|ENDMODULE|EXCEPTION|EXCLUDING|EXPORTING|INCREMENT|MATCHCODE|PARAMETER|PARTIALLY|PREFERRED|REFERENCE|REPLACING|RETURNING|SELECTION|SEPARATED|SPECIFIED|STATEMENT|TIMESTAMP|TYPE-POOL|ACCEPTING|APPENDAGE|ASSIGNING|COL_GROUP|COMPARING|CONSTANTS|DANGEROUS|IMPORTING|INSTANCES|LEFTSPACE|LOG-POINT|QUICKINFO|READ-ONLY|SCROLLING|SQLSCRIPT|STEP-LOOP|TOP-LINES|TRANSLATE|APPENDING|AUTHORITY|CHARACTER|COMPONENT|CONDITION|DIRECTORY|DUPLICATE|MESSAGING|RECEIVING|SUBSCREEN|ACCORDING|COL_TOTAL|END-LINES|ENDMETHOD|ENDSELECT|EXPANDING|EXTENSION|INCLUDING|INFOTYPES|INTERFACE|INTERVALS|LINE-SIZE|PF-STATUS|PROCEDURE|PROTECTED|REQUESTED|RESUMABLE|RIGHTPLUS|SAP-SPOOL|SECONDARY|STRUCTURE|SUBSTRING|TABLEVIEW|NUMOFCHAR|ADJACENT|ANALYSIS|ASSIGNED|BACKWARD|CHANNELS|CHECKBOX|CONTINUE|CRITICAL|DATAINFO|DD\/MM\/YY|DURATION|ENCODING|ENDCLASS|FUNCTION|LEFTPLUS|LINEFEED|MM\/DD\/YY|OVERFLOW|RECEIVED|SKIPPING|SORTABLE|STANDARD|SUBTRACT|SUPPRESS|TABSTRIP|TITLEBAR|TRUNCATE|UNASSIGN|WHENEVER|ANALYZER|COALESCE|COMMENTS|CONDENSE|DECIMALS|DEFERRED|ENDWHILE|EXPLICIT|KEYWORDS|MESSAGES|POSITION|PRIORITY|RECEIVER|RENAMING|TIMEZONE|TRAILING|ALLOCATE|CENTERED|CIRCULAR|CONTROLS|CURRENCY|DELETING|DESCRIBE|DISTANCE|ENDCATCH|EXPONENT|EXTENDED|GENERATE|IGNORING|INCLUDES|INTERNAL|MAJOR-ID|MODIFIER|NEW-LINE|OPTIONAL|PROPERTY|ROLLBACK|STARTING|SUPPLIED|ABSTRACT|CHANGING|CONTEXTS|CREATING|CUSTOMER|DATABASE|DAYLIGHT|DEFINING|DISTINCT|DIVISION|ENABLING|ENDCHAIN|ESCAPING|HARMLESS|IMPLICIT|INACTIVE|LANGUAGE|MINOR-ID|MULTIPLY|NEW-PAGE|NO-TITLE|POS_HIGH|SEPARATE|TEXTPOOL|TRANSFER|SELECTOR|DBMAXLEN|ITERATOR|SELECTOR|ARCHIVE|BIT-XOR|BYTE-CO|COLLECT|COMMENT|CURRENT|DEFAULT|DISPLAY|ENDFORM|EXTRACT|LEADING|LISTBOX|LOCATOR|MEMBERS|METHODS|NESTING|POS_LOW|PROCESS|PROVIDE|RAISING|RESERVE|SECONDS|SUMMARY|VISIBLE|BETWEEN|BIT-AND|BYTE-CS|CLEANUP|COMPUTE|CONTROL|CONVERT|DATASET|ENDCASE|FORWARD|HEADERS|HOTSPOT|INCLUDE|INVERSE|KEEPING|NO-ZERO|OBJECTS|OVERLAY|PADDING|PATTERN|PROGRAM|REFRESH|SECTION|SUMMING|TESTING|VERSION|WINDOWS|WITHOUT|BIT-NOT|BYTE-CA|BYTE-NA|CASTING|CONTEXT|COUNTRY|DYNAMIC|ENABLED|ENDLOOP|EXECUTE|FRIENDS|HANDLER|HEADING|INITIAL|\*-INPUT|LOGFILE|MAXIMUM|MINIMUM|NO-GAPS|NO-SIGN|PRAGMAS|PRIMARY|PRIVATE|REDUCED|REPLACE|REQUEST|RESULTS|UNICODE|WARNING|ALIASES|BYTE-CN|BYTE-NS|CALLING|COL_KEY|COLUMNS|CONNECT|ENDEXEC|ENTRIES|EXCLUDE|FILTERS|FURTHER|HELP-ID|LOGICAL|MAPPING|MESSAGE|NAMETAB|OPTIONS|PACKAGE|PERFORM|RECEIVE|STATICS|VARYING|BINDING|CHARLEN|GREATER|XSTRLEN|ACCEPT|APPEND|DETAIL|ELSEIF|ENDING|ENDTRY|FORMAT|FRAMES|GIVING|HASHED|HEADER|IMPORT|INSERT|MARGIN|MODULE|NATIVE|OBJECT|OFFSET|REMOTE|RESUME|SAVING|SIMPLE|SUBMIT|TABBED|TOKENS|UNIQUE|UNPACK|UPDATE|WINDOW|YELLOW|ACTUAL|ASPECT|CENTER|CURSOR|DELETE|DIALOG|DIVIDE|DURING|ERRORS|EVENTS|EXTEND|FILTER|HANDLE|HAVING|IGNORE|LITTLE|MEMORY|NO-GAP|OCCURS|OPTION|PERSON|PLACES|PUBLIC|REDUCE|REPORT|RESULT|SINGLE|SORTED|SWITCH|SYNTAX|TARGET|VALUES|WRITER|ASSERT|BLOCKS|BOUNDS|BUFFER|CHANGE|COLUMN|COMMIT|CONCAT|COPIES|CREATE|DDMMYY|DEFINE|ENDIAN|ESCAPE|EXPAND|KERNEL|LAYOUT|LEGACY|LEVELS|MMDDYY|NUMBER|OUTPUT|RANGES|READER|RETURN|SCREEN|SEARCH|SELECT|SHARED|SOURCE|STABLE|STATIC|SUBKEY|SUFFIX|TABLES|UNWIND|YYMMDD|ASSIGN|BACKUP|BEFORE|BINARY|BIT-OR|BLANKS|CLIENT|CODING|COMMON|DEMAND|DYNPRO|EXCEPT|EXISTS|EXPORT|FIELDS|GLOBAL|GROUPS|LENGTH|LOCALE|MEDIUM|METHOD|MODIFY|NESTED|OTHERS|REJECT|SCROLL|SUPPLY|SYMBOL|ENDFOR|STRLEN|ALIGN|BEGIN|BOUND|ENDAT|ENTRY|EVENT|FINAL|FLUSH|GRANT|INNER|SHORT|USING|WRITE|AFTER|BLACK|BLOCK|CLOCK|COLOR|COUNT|DUMMY|EMPTY|ENDDO|ENDON|GREEN|INDEX|INOUT|LEAVE|LEVEL|LINES|MODIF|ORDER|OUTER|RANGE|RESET|RETRY|RIGHT|SMART|SPLIT|STYLE|TABLE|THROW|UNDER|UNTIL|UPPER|UTF-8|WHERE|ALIAS|BLANK|CLEAR|CLOSE|EXACT|FETCH|FIRST|FOUND|GROUP|LLANG|LOCAL|OTHER|REGEX|SPOOL|TITLE|TYPES|VALID|WHILE|ALPHA|BOXED|CATCH|CHAIN|CHECK|CLASS|COVER|ENDIF|EQUIV|FIELD|FLOOR|FRAME|INPUT|LOWER|MATCH|NODES|PAGES|PRINT|RAISE|ROUND|SHIFT|SPACE|SPOTS|STAMP|STATE|TASKS|TIMES|TRMAC|ULINE|UNION|VALUE|WIDTH|EQUAL|LOG10|TRUNC|BLOB|CASE|CEIL|CLOB|COND|EXIT|FILE|GAPS|HOLD|INCL|INTO|KEEP|KEYS|LAST|LINE|LONG|LPAD|MAIL|MODE|OPEN|PINK|READ|ROWS|TEST|THEN|ZERO|AREA|BACK|BADI|BYTE|CAST|EDIT|EXEC|FAIL|FIND|FKEQ|FONT|FREE|GKEQ|HIDE|INIT|ITNO|LATE|LOOP|MAIN|MARK|MOVE|NEXT|NULL|RISK|ROLE|UNIT|WAIT|ZONE|BASE|CALL|CODE|DATA|DATE|FKGE|GKGE|HIGH|KIND|LEFT|LIST|MASK|MESH|NAME|NODE|PACK|PAGE|POOL|SEND|SIGN|SIZE|SOME|STOP|TASK|TEXT|TIME|USER|VARY|WITH|WORD|BLUE|CONV|COPY|DEEP|ELSE|FORM|FROM|HINT|ICON|JOIN|LIKE|LOAD|ONLY|PART|SCAN|SKIP|SORT|TYPE|UNIX|VIEW|WHEN|WORK|ACOS|ASIN|ATAN|COSH|EACH|FRAC|LESS|RTTI|SINH|SQRT|TANH|AVG|BIT|DIV|ISO|LET|OUT|PAD|SQL|ALL|CI_|CPI|END|LOB|LPI|MAX|MIN|NEW|OLE|RUN|SET|\?TO|YES|ABS|ADD|AND|BIG|FOR|HDB|JOB|LOW|NOT|SAP|TRY|VIA|XML|ANY|GET|IDS|KEY|MOD|OFF|PUT|RAW|RED|REF|SUM|TAB|XSD|CNT|COS|EXP|LOG|SIN|TAN|XOR|AT|CO|CP|DO|GT|ID|IF|NS|OR|BT|CA|CS|GE|NA|NB|EQ|IN|LT|NE|NO|OF|ON|PF|TO|AS|BY|CN|IS|LE|NP|UP|E|I|M|O|Z|C|X)\b/i,lookbehind:!0},number:/\b\d+\b/,operator:{pattern:/(\s)(?:\*\*?|<[=>]?|>=?|\?=|[-+\/=])(?=\s)/,lookbehind:!0},"string-operator":{pattern:/(\s)&&?(?=\s)/,lookbehind:!0,alias:"keyword"},"token-operator":[{pattern:/(\w)(?:->?|=>|[~|{}])(?=\w)/,lookbehind:!0,alias:"punctuation"},{pattern:/[|{}]/,alias:"punctuation"}],punctuation:/[,.:()]/},Prism.languages.actionscript=Prism.languages.extend("javascript",{keyword:/\b(?:as|break|case|catch|class|const|default|delete|do|else|extends|finally|for|function|if|implements|import|in|instanceof|interface|internal|is|native|new|null|package|private|protected|public|return|super|switch|this|throw|try|typeof|use|var|void|while|with|dynamic|each|final|get|include|namespace|native|override|set|static)\b/,operator:/\+\+|--|(?:[+\-*\/%^]|&&?|\|\|?|<>?>?|[!=]=?)=?|[~?@]/}),Prism.languages.actionscript["class-name"].alias="function",Prism.languages.markup&&Prism.languages.insertBefore("actionscript","string",{xml:{pattern:/(^|[^.])<\/?\w+(?:\s+[^\s>\/=]+=("|')(?:\\\1|\\?(?!\1)[\w\W])*\2)*\s*\/?>/,lookbehind:!0,inside:{rest:Prism.languages.markup}}}),Prism.languages.ada={comment:/--.*/,string:/"(?:""|[^"\r\f\n])*"/i,number:[{pattern:/\b[0-9](?:_?[0-9])*#[0-9A-F](?:_?[0-9A-F])*(?:\.[0-9A-F](?:_?[0-9A-F])*)?#(?:E[+-]?[0-9](?:_?[0-9])*)?/i},{pattern:/\b[0-9](?:_?[0-9])*(?:\.[0-9](?:_?[0-9])*)?(?:E[+-]?[0-9](?:_?[0-9])*)?\b/i}],"attr-name":/\b'\w+/i,keyword:/\b(?:abort|abs|abstract|accept|access|aliased|all|and|array|at|begin|body|case|constant|declare|delay|delta|digits|do|else|new|return|elsif|end|entry|exception|exit|for|function|generic|goto|if|in|interface|is|limited|loop|mod|not|null|of|others|out|overriding|package|pragma|private|procedure|protected|raise|range|record|rem|renames|requeue|reverse|select|separate|some|subtype|synchronized|tagged|task|terminate|then|type|until|use|when|while|with|xor)\b/i,"boolean":/\b(?:true|false)\b/i,operator:/<[=>]?|>=?|=>?|:=|\/=?|\*\*?|[&+-]/,punctuation:/\.\.?|[,;():]/,"char":/'.'/,variable:/\b[a-z](?:[_a-z\d])*\b/i},Prism.languages.apacheconf={comment:/#.*/,"directive-inline":{pattern:/^(\s*)\b(AcceptFilter|AcceptPathInfo|AccessFileName|Action|AddAlt|AddAltByEncoding|AddAltByType|AddCharset|AddDefaultCharset|AddDescription|AddEncoding|AddHandler|AddIcon|AddIconByEncoding|AddIconByType|AddInputFilter|AddLanguage|AddModuleInfo|AddOutputFilter|AddOutputFilterByType|AddType|Alias|AliasMatch|Allow|AllowCONNECT|AllowEncodedSlashes|AllowMethods|AllowOverride|AllowOverrideList|Anonymous|Anonymous_LogEmail|Anonymous_MustGiveEmail|Anonymous_NoUserID|Anonymous_VerifyEmail|AsyncRequestWorkerFactor|AuthBasicAuthoritative|AuthBasicFake|AuthBasicProvider|AuthBasicUseDigestAlgorithm|AuthDBDUserPWQuery|AuthDBDUserRealmQuery|AuthDBMGroupFile|AuthDBMType|AuthDBMUserFile|AuthDigestAlgorithm|AuthDigestDomain|AuthDigestNonceLifetime|AuthDigestProvider|AuthDigestQop|AuthDigestShmemSize|AuthFormAuthoritative|AuthFormBody|AuthFormDisableNoStore|AuthFormFakeBasicAuth|AuthFormLocation|AuthFormLoginRequiredLocation|AuthFormLoginSuccessLocation|AuthFormLogoutLocation|AuthFormMethod|AuthFormMimetype|AuthFormPassword|AuthFormProvider|AuthFormSitePassphrase|AuthFormSize|AuthFormUsername|AuthGroupFile|AuthLDAPAuthorizePrefix|AuthLDAPBindAuthoritative|AuthLDAPBindDN|AuthLDAPBindPassword|AuthLDAPCharsetConfig|AuthLDAPCompareAsUser|AuthLDAPCompareDNOnServer|AuthLDAPDereferenceAliases|AuthLDAPGroupAttribute|AuthLDAPGroupAttributeIsDN|AuthLDAPInitialBindAsUser|AuthLDAPInitialBindPattern|AuthLDAPMaxSubGroupDepth|AuthLDAPRemoteUserAttribute|AuthLDAPRemoteUserIsDN|AuthLDAPSearchAsUser|AuthLDAPSubGroupAttribute|AuthLDAPSubGroupClass|AuthLDAPUrl|AuthMerging|AuthName|AuthnCacheContext|AuthnCacheEnable|AuthnCacheProvideFor|AuthnCacheSOCache|AuthnCacheTimeout|AuthnzFcgiCheckAuthnProvider|AuthnzFcgiDefineProvider|AuthType|AuthUserFile|AuthzDBDLoginToReferer|AuthzDBDQuery|AuthzDBDRedirectQuery|AuthzDBMType|AuthzSendForbiddenOnFailure|BalancerGrowth|BalancerInherit|BalancerMember|BalancerPersist|BrowserMatch|BrowserMatchNoCase|BufferedLogs|BufferSize|CacheDefaultExpire|CacheDetailHeader|CacheDirLength|CacheDirLevels|CacheDisable|CacheEnable|CacheFile|CacheHeader|CacheIgnoreCacheControl|CacheIgnoreHeaders|CacheIgnoreNoLastMod|CacheIgnoreQueryString|CacheIgnoreURLSessionIdentifiers|CacheKeyBaseURL|CacheLastModifiedFactor|CacheLock|CacheLockMaxAge|CacheLockPath|CacheMaxExpire|CacheMaxFileSize|CacheMinExpire|CacheMinFileSize|CacheNegotiatedDocs|CacheQuickHandler|CacheReadSize|CacheReadTime|CacheRoot|CacheSocache|CacheSocacheMaxSize|CacheSocacheMaxTime|CacheSocacheMinTime|CacheSocacheReadSize|CacheSocacheReadTime|CacheStaleOnError|CacheStoreExpired|CacheStoreNoStore|CacheStorePrivate|CGIDScriptTimeout|CGIMapExtension|CharsetDefault|CharsetOptions|CharsetSourceEnc|CheckCaseOnly|CheckSpelling|ChrootDir|ContentDigest|CookieDomain|CookieExpires|CookieName|CookieStyle|CookieTracking|CoreDumpDirectory|CustomLog|Dav|DavDepthInfinity|DavGenericLockDB|DavLockDB|DavMinTimeout|DBDExptime|DBDInitSQL|DBDKeep|DBDMax|DBDMin|DBDParams|DBDPersist|DBDPrepareSQL|DBDriver|DefaultIcon|DefaultLanguage|DefaultRuntimeDir|DefaultType|Define|DeflateBufferSize|DeflateCompressionLevel|DeflateFilterNote|DeflateInflateLimitRequestBody|DeflateInflateRatioBurst|DeflateInflateRatioLimit|DeflateMemLevel|DeflateWindowSize|Deny|DirectoryCheckHandler|DirectoryIndex|DirectoryIndexRedirect|DirectorySlash|DocumentRoot|DTracePrivileges|DumpIOInput|DumpIOOutput|EnableExceptionHook|EnableMMAP|EnableSendfile|Error|ErrorDocument|ErrorLog|ErrorLogFormat|Example|ExpiresActive|ExpiresByType|ExpiresDefault|ExtendedStatus|ExtFilterDefine|ExtFilterOptions|FallbackResource|FileETag|FilterChain|FilterDeclare|FilterProtocol|FilterProvider|FilterTrace|ForceLanguagePriority|ForceType|ForensicLog|GprofDir|GracefulShutdownTimeout|Group|Header|HeaderName|HeartbeatAddress|HeartbeatListen|HeartbeatMaxServers|HeartbeatStorage|HeartbeatStorage|HostnameLookups|IdentityCheck|IdentityCheckTimeout|ImapBase|ImapDefault|ImapMenu|Include|IncludeOptional|IndexHeadInsert|IndexIgnore|IndexIgnoreReset|IndexOptions|IndexOrderDefault|IndexStyleSheet|InputSed|ISAPIAppendLogToErrors|ISAPIAppendLogToQuery|ISAPICacheFile|ISAPIFakeAsync|ISAPILogNotSupported|ISAPIReadAheadBuffer|KeepAlive|KeepAliveTimeout|KeptBodySize|LanguagePriority|LDAPCacheEntries|LDAPCacheTTL|LDAPConnectionPoolTTL|LDAPConnectionTimeout|LDAPLibraryDebug|LDAPOpCacheEntries|LDAPOpCacheTTL|LDAPReferralHopLimit|LDAPReferrals|LDAPRetries|LDAPRetryDelay|LDAPSharedCacheFile|LDAPSharedCacheSize|LDAPTimeout|LDAPTrustedClientCert|LDAPTrustedGlobalCert|LDAPTrustedMode|LDAPVerifyServerCert|LimitInternalRecursion|LimitRequestBody|LimitRequestFields|LimitRequestFieldSize|LimitRequestLine|LimitXMLRequestBody|Listen|ListenBackLog|LoadFile|LoadModule|LogFormat|LogLevel|LogMessage|LuaAuthzProvider|LuaCodeCache|LuaHookAccessChecker|LuaHookAuthChecker|LuaHookCheckUserID|LuaHookFixups|LuaHookInsertFilter|LuaHookLog|LuaHookMapToStorage|LuaHookTranslateName|LuaHookTypeChecker|LuaInherit|LuaInputFilter|LuaMapHandler|LuaOutputFilter|LuaPackageCPath|LuaPackagePath|LuaQuickHandler|LuaRoot|LuaScope|MaxConnectionsPerChild|MaxKeepAliveRequests|MaxMemFree|MaxRangeOverlaps|MaxRangeReversals|MaxRanges|MaxRequestWorkers|MaxSpareServers|MaxSpareThreads|MaxThreads|MergeTrailers|MetaDir|MetaFiles|MetaSuffix|MimeMagicFile|MinSpareServers|MinSpareThreads|MMapFile|ModemStandard|ModMimeUsePathInfo|MultiviewsMatch|Mutex|NameVirtualHost|NoProxy|NWSSLTrustedCerts|NWSSLUpgradeable|Options|Order|OutputSed|PassEnv|PidFile|PrivilegesMode|Protocol|ProtocolEcho|ProxyAddHeaders|ProxyBadHeader|ProxyBlock|ProxyDomain|ProxyErrorOverride|ProxyExpressDBMFile|ProxyExpressDBMType|ProxyExpressEnable|ProxyFtpDirCharset|ProxyFtpEscapeWildcards|ProxyFtpListOnWildcard|ProxyHTMLBufSize|ProxyHTMLCharsetOut|ProxyHTMLDocType|ProxyHTMLEnable|ProxyHTMLEvents|ProxyHTMLExtended|ProxyHTMLFixups|ProxyHTMLInterp|ProxyHTMLLinks|ProxyHTMLMeta|ProxyHTMLStripComments|ProxyHTMLURLMap|ProxyIOBufferSize|ProxyMaxForwards|ProxyPass|ProxyPassInherit|ProxyPassInterpolateEnv|ProxyPassMatch|ProxyPassReverse|ProxyPassReverseCookieDomain|ProxyPassReverseCookiePath|ProxyPreserveHost|ProxyReceiveBufferSize|ProxyRemote|ProxyRemoteMatch|ProxyRequests|ProxySCGIInternalRedirect|ProxySCGISendfile|ProxySet|ProxySourceAddress|ProxyStatus|ProxyTimeout|ProxyVia|ReadmeName|ReceiveBufferSize|Redirect|RedirectMatch|RedirectPermanent|RedirectTemp|ReflectorHeader|RemoteIPHeader|RemoteIPInternalProxy|RemoteIPInternalProxyList|RemoteIPProxiesHeader|RemoteIPTrustedProxy|RemoteIPTrustedProxyList|RemoveCharset|RemoveEncoding|RemoveHandler|RemoveInputFilter|RemoveLanguage|RemoveOutputFilter|RemoveType|RequestHeader|RequestReadTimeout|Require|RewriteBase|RewriteCond|RewriteEngine|RewriteMap|RewriteOptions|RewriteRule|RLimitCPU|RLimitMEM|RLimitNPROC|Satisfy|ScoreBoardFile|Script|ScriptAlias|ScriptAliasMatch|ScriptInterpreterSource|ScriptLog|ScriptLogBuffer|ScriptLogLength|ScriptSock|SecureListen|SeeRequestTail|SendBufferSize|ServerAdmin|ServerAlias|ServerLimit|ServerName|ServerPath|ServerRoot|ServerSignature|ServerTokens|Session|SessionCookieName|SessionCookieName2|SessionCookieRemove|SessionCryptoCipher|SessionCryptoDriver|SessionCryptoPassphrase|SessionCryptoPassphraseFile|SessionDBDCookieName|SessionDBDCookieName2|SessionDBDCookieRemove|SessionDBDDeleteLabel|SessionDBDInsertLabel|SessionDBDPerUser|SessionDBDSelectLabel|SessionDBDUpdateLabel|SessionEnv|SessionExclude|SessionHeader|SessionInclude|SessionMaxAge|SetEnv|SetEnvIf|SetEnvIfExpr|SetEnvIfNoCase|SetHandler|SetInputFilter|SetOutputFilter|SSIEndTag|SSIErrorMsg|SSIETag|SSILastModified|SSILegacyExprParser|SSIStartTag|SSITimeFormat|SSIUndefinedEcho|SSLCACertificateFile|SSLCACertificatePath|SSLCADNRequestFile|SSLCADNRequestPath|SSLCARevocationCheck|SSLCARevocationFile|SSLCARevocationPath|SSLCertificateChainFile|SSLCertificateFile|SSLCertificateKeyFile|SSLCipherSuite|SSLCompression|SSLCryptoDevice|SSLEngine|SSLFIPS|SSLHonorCipherOrder|SSLInsecureRenegotiation|SSLOCSPDefaultResponder|SSLOCSPEnable|SSLOCSPOverrideResponder|SSLOCSPResponderTimeout|SSLOCSPResponseMaxAge|SSLOCSPResponseTimeSkew|SSLOCSPUseRequestNonce|SSLOpenSSLConfCmd|SSLOptions|SSLPassPhraseDialog|SSLProtocol|SSLProxyCACertificateFile|SSLProxyCACertificatePath|SSLProxyCARevocationCheck|SSLProxyCARevocationFile|SSLProxyCARevocationPath|SSLProxyCheckPeerCN|SSLProxyCheckPeerExpire|SSLProxyCheckPeerName|SSLProxyCipherSuite|SSLProxyEngine|SSLProxyMachineCertificateChainFile|SSLProxyMachineCertificateFile|SSLProxyMachineCertificatePath|SSLProxyProtocol|SSLProxyVerify|SSLProxyVerifyDepth|SSLRandomSeed|SSLRenegBufferSize|SSLRequire|SSLRequireSSL|SSLSessionCache|SSLSessionCacheTimeout|SSLSessionTicketKeyFile|SSLSRPUnknownUserSeed|SSLSRPVerifierFile|SSLStaplingCache|SSLStaplingErrorCacheTimeout|SSLStaplingFakeTryLater|SSLStaplingForceURL|SSLStaplingResponderTimeout|SSLStaplingResponseMaxAge|SSLStaplingResponseTimeSkew|SSLStaplingReturnResponderErrors|SSLStaplingStandardCacheTimeout|SSLStrictSNIVHostCheck|SSLUserName|SSLUseStapling|SSLVerifyClient|SSLVerifyDepth|StartServers|StartThreads|Substitute|Suexec|SuexecUserGroup|ThreadLimit|ThreadsPerChild|ThreadStackSize|TimeOut|TraceEnable|TransferLog|TypesConfig|UnDefine|UndefMacro|UnsetEnv|Use|UseCanonicalName|UseCanonicalPhysicalPort|User|UserDir|VHostCGIMode|VHostCGIPrivs|VHostGroup|VHostPrivs|VHostSecure|VHostUser|VirtualDocumentRoot|VirtualDocumentRootIP|VirtualScriptAlias|VirtualScriptAliasIP|WatchdogInterval|XBitHack|xml2EncAlias|xml2EncDefault|xml2StartParse)\b/im,lookbehind:!0,alias:"property"},"directive-block":{pattern:/<\/?\b(AuthnProviderAlias|AuthzProviderAlias|Directory|DirectoryMatch|Else|ElseIf|Files|FilesMatch|If|IfDefine|IfModule|IfVersion|Limit|LimitExcept|Location|LocationMatch|Macro|Proxy|RequireAll|RequireAny|RequireNone|VirtualHost)\b *.*>/i,inside:{"directive-block":{pattern:/^<\/?\w+/,inside:{punctuation:/^<\/?/},alias:"tag"},"directive-block-parameter":{pattern:/.*[^>]/,inside:{punctuation:/:/,string:{pattern:/("|').*\1/,inside:{variable:/(\$|%)\{?(\w\.?(\+|\-|:)?)+\}?/}}},alias:"attr-value"},punctuation:/>/},alias:"tag"},"directive-flags":{pattern:/\[(\w,?)+\]/,alias:"keyword"},string:{pattern:/("|').*\1/,inside:{variable:/(\$|%)\{?(\w\.?(\+|\-|:)?)+\}?/}},variable:/(\$|%)\{?(\w\.?(\+|\-|:)?)+\}?/,regex:/\^?.*\$|\^.*\$?/},Prism.languages.apl={comment:/(?:\u235d|#[! ]).*$/m,string:/'(?:[^'\r\n]|'')*'/,number:/\xaf?(?:\d*\.?\d+(?:e[+\xaf]?\d+)?|\xaf|\u221e)(?:j\xaf?(?:\d*\.?\d+(?:e[\+\xaf]?\d+)?|\xaf|\u221e))?/i,statement:/:[A-Z][a-z][A-Za-z]*\b/,"system-function":{pattern:/\u2395[A-Z]+/i,alias:"function"},constant:/[\u236c\u233e#\u2395\u235e]/,"function":/[-+\xd7\xf7\u2308\u230a\u2223|\u2373?*\u235f\u25cb!\u2339<\u2264=>\u2265\u2260\u2261\u2262\u220a\u2377\u222a\u2229~\u2228\u2227\u2371\u2372\u2374,\u236a\u233d\u2296\u2349\u2191\u2193\u2282\u2283\u2337\u234b\u2352\u22a4\u22a5\u2355\u234e\u22a3\u22a2\u2341\u2342\u2248\u236f\u2197\xa4\u2192]/,"monadic-operator":{pattern:/[\\\/\u233f\u2340\xa8\u2368\u2336&\u2225]/,alias:"operator"},"dyadic-operator":{pattern:/[.\u2363\u2360\u2364\u2218\u2338]/,alias:"operator"},assignment:{pattern:/\u2190/,alias:"keyword"},punctuation:/[\[;\]()\u25c7\u22c4]/,dfn:{pattern:/[{}\u237a\u2375\u2376\u2379\u2207\u236b:]/,alias:"builtin"}},Prism.languages.applescript={comment:[/\(\*(?:\(\*[\w\W]*?\*\)|[\w\W])*?\*\)/,/--.+/,/#.+/],string:/"(?:\\?.)*?"/,number:/\b-?\d*\.?\d+([Ee]-?\d+)?\b/,operator:[/[&=\u2260\u2264\u2265*+\-\/\xf7^]|[<>]=?/,/\b(?:(?:start|begin|end)s? with|(?:(?:does not|doesn't) contain|contains?)|(?:is|isn't|is not) (?:in|contained by)|(?:(?:is|isn't|is not) )?(?:greater|less) than(?: or equal)?(?: to)?|(?:(?:does not|doesn't) come|comes) (?:before|after)|(?:is|isn't|is not) equal(?: to)?|(?:(?:does not|doesn't) equal|equals|equal to|isn't|is not)|(?:a )?(?:ref(?: to)?|reference to)|(?:and|or|div|mod|as|not))\b/],keyword:/\b(?:about|above|after|against|apart from|around|aside from|at|back|before|beginning|behind|below|beneath|beside|between|but|by|considering|continue|copy|does|eighth|else|end|equal|error|every|exit|false|fifth|first|for|fourth|from|front|get|given|global|if|ignoring|in|instead of|into|is|it|its|last|local|me|middle|my|ninth|of|on|onto|out of|over|prop|property|put|repeat|return|returning|second|set|seventh|since|sixth|some|tell|tenth|that|the|then|third|through|thru|timeout|times|to|transaction|true|try|until|where|while|whose|with|without)\b/,"class":{pattern:/\b(?:alias|application|boolean|class|constant|date|file|integer|list|number|POSIX file|real|record|reference|RGB color|script|text|centimetres|centimeters|feet|inches|kilometres|kilometers|metres|meters|miles|yards|square feet|square kilometres|square kilometers|square metres|square meters|square miles|square yards|cubic centimetres|cubic centimeters|cubic feet|cubic inches|cubic metres|cubic meters|cubic yards|gallons|litres|liters|quarts|grams|kilograms|ounces|pounds|degrees Celsius|degrees Fahrenheit|degrees Kelvin)\b/,alias:"builtin"},punctuation:/[{}():,\xac\xab\xbb\u300a\u300b]/},function(e){var t={pattern:/(^[ \t]*)\[(?!\[)(?:(["'$`])(?:(?!\2)[^\\]|\\.)*\2|\[(?:[^\]\\]|\\.)*\]|[^\]\\]|\\.)*\]/m,lookbehind:!0,inside:{quoted:{pattern:/([$`])(?:(?!\1)[^\\]|\\.)*\1/,inside:{punctuation:/^[$`]|[$`]$/}},interpreted:{pattern:/'(?:[^'\\]|\\.)*'/,inside:{punctuation:/^'|'$/}},string:/"(?:[^"\\]|\\.)*"/,variable:/\w+(?==)/,punctuation:/^\[|\]$|,/,operator:/=/,"attr-value":/(?!^\s+$).+/}};e.languages.asciidoc={"comment-block":{pattern:/^(\/{4,})(?:\r?\n|\r)(?:.*(?:\r?\n|\r))*?\1/m,alias:"comment" +},table:{pattern:/^\|={3,}(?:(?:\r?\n|\r).*)*?(?:\r?\n|\r)\|={3,}$/m,inside:{specifiers:{pattern:/(?!\|)(?:(?:(?:\d+(?:\.\d+)?|\.\d+)[+*])?(?:[<^>](?:\.[<^>])?|\.[<^>])?[a-z]*)(?=\|)/,alias:"attr-value"},punctuation:{pattern:/(^|[^\\])[|!]=*/,lookbehind:!0}}},"passthrough-block":{pattern:/^(\+{4,})(?:\r?\n|\r)(?:.*(?:\r?\n|\r))*?\1$/m,inside:{punctuation:/^\++|\++$/}},"literal-block":{pattern:/^(-{4,}|\.{4,})(?:\r?\n|\r)(?:.*(?:\r?\n|\r))*?\1$/m,inside:{punctuation:/^(?:-+|\.+)|(?:-+|\.+)$/}},"other-block":{pattern:/^(--|\*{4,}|_{4,}|={4,})(?:\r?\n|\r)(?:.*(?:\r?\n|\r))*?\1$/m,inside:{punctuation:/^(?:-+|\*+|_+|=+)|(?:-+|\*+|_+|=+)$/}},"list-punctuation":{pattern:/(^[ \t]*)(?:-|\*{1,5}|\.{1,5}|(?:[a-z]|\d+)\.|[xvi]+\))(?= )/im,lookbehind:!0,alias:"punctuation"},"list-label":{pattern:/(^[ \t]*)[a-z\d].+(?::{2,4}|;;)(?=\s)/im,lookbehind:!0,alias:"symbol"},"indented-block":{pattern:/((\r?\n|\r)\2)([ \t]+)\S.*(?:(?:\r?\n|\r)\3.+)*(?=\2{2}|$)/,lookbehind:!0},comment:/^\/\/.*/m,title:{pattern:/^.+(?:\r?\n|\r)(?:={3,}|-{3,}|~{3,}|\^{3,}|\+{3,})$|^={1,5} +.+|^\.(?![\s.]).*/m,alias:"important",inside:{punctuation:/^(?:\.|=+)|(?:=+|-+|~+|\^+|\++)$/}},"attribute-entry":{pattern:/^:[^:\r\n]+:(?: .*?(?: \+(?:\r?\n|\r).*?)*)?$/m,alias:"tag"},attributes:t,hr:{pattern:/^'{3,}$/m,alias:"punctuation"},"page-break":{pattern:/^<{3,}$/m,alias:"punctuation"},admonition:{pattern:/^(?:TIP|NOTE|IMPORTANT|WARNING|CAUTION):/m,alias:"keyword"},callout:[{pattern:/(^[ \t]*)/m,lookbehind:!0,alias:"symbol"},{pattern:/<\d+>/,alias:"symbol"}],macro:{pattern:/\b[a-z\d][a-z\d-]*::?(?:(?:\S+)??\[(?:[^\]\\"]|(["'])(?:(?!\1)[^\\]|\\.)*\1|\\.)*\])/,inside:{"function":/^[a-z\d-]+(?=:)/,punctuation:/^::?/,attributes:{pattern:/(?:\[(?:[^\]\\"]|(["'])(?:(?!\1)[^\\]|\\.)*\1|\\.)*\])/,inside:t.inside}}},inline:{pattern:/(^|[^\\])(?:(?:\B\[(?:[^\]\\"]|(["'])(?:(?!\2)[^\\]|\\.)*\2|\\.)*\])?(?:\b_(?!\s)(?: _|[^_\\\r\n]|\\.)+(?:(?:\r?\n|\r)(?: _|[^_\\\r\n]|\\.)+)*_\b|\B``(?!\s).+?(?:(?:\r?\n|\r).+?)*''\B|\B`(?!\s)(?: ['`]|.)+?(?:(?:\r?\n|\r)(?: ['`]|.)+?)*['`]\B|\B(['*+#])(?!\s)(?: \3|(?!\3)[^\\\r\n]|\\.)+(?:(?:\r?\n|\r)(?: \3|(?!\3)[^\\\r\n]|\\.)+)*\3\B)|(?:\[(?:[^\]\\"]|(["'])(?:(?!\4)[^\\]|\\.)*\4|\\.)*\])?(?:(__|\*\*|\+\+\+?|##|\$\$|[~^]).+?(?:(?:\r?\n|\r).+?)*\5|\{[^}\r\n]+\}|\[\[\[?.+?(?:(?:\r?\n|\r).+?)*\]?\]\]|<<.+?(?:(?:\r?\n|\r).+?)*>>|\(\(\(?.+?(?:(?:\r?\n|\r).+?)*\)?\)\)))/m,lookbehind:!0,inside:{attributes:t,url:{pattern:/^(?:\[\[\[?.+?\]?\]\]|<<.+?>>)$/,inside:{punctuation:/^(?:\[\[\[?|<<)|(?:\]\]\]?|>>)$/}},"attribute-ref":{pattern:/^\{.+\}$/,inside:{variable:{pattern:/(^\{)[a-z\d,+_-]+/,lookbehind:!0},operator:/^[=?!#%@$]|!(?=[:}])/,punctuation:/^\{|\}$|::?/}},italic:{pattern:/^(['_])[\s\S]+\1$/,inside:{punctuation:/^(?:''?|__?)|(?:''?|__?)$/}},bold:{pattern:/^\*[\s\S]+\*$/,inside:{punctuation:/^\*\*?|\*\*?$/}},punctuation:/^(?:``?|\+{1,3}|##?|\$\$|[~^]|\(\(\(?)|(?:''?|\+{1,3}|##?|\$\$|[~^`]|\)?\)\))$/}},replacement:{pattern:/\((?:C|TM|R)\)/,alias:"builtin"},entity:/&#?[\da-z]{1,8};/i,"line-continuation":{pattern:/(^| )\+$/m,lookbehind:!0,alias:"punctuation"}},t.inside.interpreted.inside.rest={macro:e.languages.asciidoc.macro,inline:e.languages.asciidoc.inline,replacement:e.languages.asciidoc.replacement,entity:e.languages.asciidoc.entity},e.languages.asciidoc["passthrough-block"].inside.rest={macro:e.languages.asciidoc.macro},e.languages.asciidoc["literal-block"].inside.rest={callout:e.languages.asciidoc.callout},e.languages.asciidoc.table.inside.rest={"comment-block":e.languages.asciidoc["comment-block"],"passthrough-block":e.languages.asciidoc["passthrough-block"],"literal-block":e.languages.asciidoc["literal-block"],"other-block":e.languages.asciidoc["other-block"],"list-punctuation":e.languages.asciidoc["list-punctuation"],"indented-block":e.languages.asciidoc["indented-block"],comment:e.languages.asciidoc.comment,title:e.languages.asciidoc.title,"attribute-entry":e.languages.asciidoc["attribute-entry"],attributes:e.languages.asciidoc.attributes,hr:e.languages.asciidoc.hr,"page-break":e.languages.asciidoc["page-break"],admonition:e.languages.asciidoc.admonition,"list-label":e.languages.asciidoc["list-label"],callout:e.languages.asciidoc.callout,macro:e.languages.asciidoc.macro,inline:e.languages.asciidoc.inline,replacement:e.languages.asciidoc.replacement,entity:e.languages.asciidoc.entity,"line-continuation":e.languages.asciidoc["line-continuation"]},e.languages.asciidoc["other-block"].inside.rest={table:e.languages.asciidoc.table,"list-punctuation":e.languages.asciidoc["list-punctuation"],"indented-block":e.languages.asciidoc["indented-block"],comment:e.languages.asciidoc.comment,"attribute-entry":e.languages.asciidoc["attribute-entry"],attributes:e.languages.asciidoc.attributes,hr:e.languages.asciidoc.hr,"page-break":e.languages.asciidoc["page-break"],admonition:e.languages.asciidoc.admonition,"list-label":e.languages.asciidoc["list-label"],macro:e.languages.asciidoc.macro,inline:e.languages.asciidoc.inline,replacement:e.languages.asciidoc.replacement,entity:e.languages.asciidoc.entity,"line-continuation":e.languages.asciidoc["line-continuation"]},e.languages.asciidoc.title.inside.rest={macro:e.languages.asciidoc.macro,inline:e.languages.asciidoc.inline,replacement:e.languages.asciidoc.replacement,entity:e.languages.asciidoc.entity},e.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})}(Prism),Prism.languages.aspnet=Prism.languages.extend("markup",{"page-directive tag":{pattern:/<%\s*@.*%>/i,inside:{"page-directive tag":/<%\s*@\s*(?:Assembly|Control|Implements|Import|Master(?:Type)?|OutputCache|Page|PreviousPageType|Reference|Register)?|%>/i,rest:Prism.languages.markup.tag.inside}},"directive tag":{pattern:/<%.*%>/i,inside:{"directive tag":/<%\s*?[$=%#:]{0,2}|%>/i,rest:Prism.languages.csharp}}}),Prism.languages.aspnet.tag.pattern=/<(?!%)\/?[^\s>\/]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,Prism.languages.insertBefore("inside","punctuation",{"directive tag":Prism.languages.aspnet["directive tag"]},Prism.languages.aspnet.tag.inside["attr-value"]),Prism.languages.insertBefore("aspnet","comment",{"asp comment":/<%--[\w\W]*?--%>/}),Prism.languages.insertBefore("aspnet",Prism.languages.javascript?"script":"tag",{"asp script":{pattern:/()[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.csharp||{}}}),Prism.languages.autoit={comment:[/;.*/,{pattern:/(^\s*)#(?:comments-start|cs)[\s\S]*?^\s*#(?:comments-end|ce)/m,lookbehind:!0}],url:{pattern:/(^\s*#include\s+)(?:<[^\r\n>]+>|"[^\r\n"]+")/m,lookbehind:!0},string:{pattern:/(["'])(?:\1\1|(?!\1)[^\r\n])*\1/,inside:{variable:/([%$@])\w+\1/}},directive:{pattern:/(^\s*)#\w+/m,lookbehind:!0,alias:"keyword"},"function":/\b\w+(?=\()/,variable:/[$@]\w+/,keyword:/\b(?:Case|Const|Continue(?:Case|Loop)|Default|Dim|Do|Else(?:If)?|End(?:Func|If|Select|Switch|With)|Enum|Exit(?:Loop)?|For|Func|Global|If|In|Local|Next|Null|ReDim|Select|Static|Step|Switch|Then|To|Until|Volatile|WEnd|While|With)\b/i,number:/\b(?:0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)\b/i,"boolean":/\b(?:True|False)\b/i,operator:/<[=>]?|[-+*\/=&>]=?|[?^]|\b(?:And|Or|Not)\b/i,punctuation:/[\[\]().,:]/},Prism.languages.autohotkey={comment:{pattern:/(^[^";\n]*("[^"\n]*?"[^"\n]*?)*)(;.*$|^\s*\/\*[\s\S]*\n\*\/)/m,lookbehind:!0},string:/"(([^"\n\r]|"")*)"/m,"function":/[^\(\); \t,\n\+\*\-=\?>:\\\/<&%\[\]]+?(?=\()/m,tag:/^[ \t]*[^\s:]+?(?=:(?:[^:]|$))/m,variable:/%\w+%/,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,operator:/\?|\/\/?=?|:=|\|[=|]?|&[=&]?|\+[=+]?|-[=-]?|\*[=*]?|<(?:<=?|>|=)?|>>?=?|[.^!=~]=?|\b(?:AND|NOT|OR)\b/,punctuation:/[\{}[\]\(\):,]/,"boolean":/\b(true|false)\b/,selector:/\b(AutoTrim|BlockInput|Break|Click|ClipWait|Continue|Control|ControlClick|ControlFocus|ControlGet|ControlGetFocus|ControlGetPos|ControlGetText|ControlMove|ControlSend|ControlSendRaw|ControlSetText|CoordMode|Critical|DetectHiddenText|DetectHiddenWindows|Drive|DriveGet|DriveSpaceFree|EnvAdd|EnvDiv|EnvGet|EnvMult|EnvSet|EnvSub|EnvUpdate|Exit|ExitApp|FileAppend|FileCopy|FileCopyDir|FileCreateDir|FileCreateShortcut|FileDelete|FileEncoding|FileGetAttrib|FileGetShortcut|FileGetSize|FileGetTime|FileGetVersion|FileInstall|FileMove|FileMoveDir|FileRead|FileReadLine|FileRecycle|FileRecycleEmpty|FileRemoveDir|FileSelectFile|FileSelectFolder|FileSetAttrib|FileSetTime|FormatTime|GetKeyState|Gosub|Goto|GroupActivate|GroupAdd|GroupClose|GroupDeactivate|Gui|GuiControl|GuiControlGet|Hotkey|ImageSearch|IniDelete|IniRead|IniWrite|Input|InputBox|KeyWait|ListHotkeys|ListLines|ListVars|Loop|Menu|MouseClick|MouseClickDrag|MouseGetPos|MouseMove|MsgBox|OnExit|OutputDebug|Pause|PixelGetColor|PixelSearch|PostMessage|Process|Progress|Random|RegDelete|RegRead|RegWrite|Reload|Repeat|Return|Run|RunAs|RunWait|Send|SendEvent|SendInput|SendMessage|SendMode|SendPlay|SendRaw|SetBatchLines|SetCapslockState|SetControlDelay|SetDefaultMouseSpeed|SetEnv|SetFormat|SetKeyDelay|SetMouseDelay|SetNumlockState|SetScrollLockState|SetStoreCapslockMode|SetTimer|SetTitleMatchMode|SetWinDelay|SetWorkingDir|Shutdown|Sleep|Sort|SoundBeep|SoundGet|SoundGetWaveVolume|SoundPlay|SoundSet|SoundSetWaveVolume|SplashImage|SplashTextOff|SplashTextOn|SplitPath|StatusBarGetText|StatusBarWait|StringCaseSense|StringGetPos|StringLeft|StringLen|StringLower|StringMid|StringReplace|StringRight|StringSplit|StringTrimLeft|StringTrimRight|StringUpper|Suspend|SysGet|Thread|ToolTip|Transform|TrayTip|URLDownloadToFile|WinActivate|WinActivateBottom|WinClose|WinGet|WinGetActiveStats|WinGetActiveTitle|WinGetClass|WinGetPos|WinGetText|WinGetTitle|WinHide|WinKill|WinMaximize|WinMenuSelectItem|WinMinimize|WinMinimizeAll|WinMinimizeAllUndo|WinMove|WinRestore|WinSet|WinSetTitle|WinShow|WinWait|WinWaitActive|WinWaitClose|WinWaitNotActive)\b/i,constant:/\b(a_ahkpath|a_ahkversion|a_appdata|a_appdatacommon|a_autotrim|a_batchlines|a_caretx|a_carety|a_computername|a_controldelay|a_cursor|a_dd|a_ddd|a_dddd|a_defaultmousespeed|a_desktop|a_desktopcommon|a_detecthiddentext|a_detecthiddenwindows|a_endchar|a_eventinfo|a_exitreason|a_formatfloat|a_formatinteger|a_gui|a_guievent|a_guicontrol|a_guicontrolevent|a_guiheight|a_guiwidth|a_guix|a_guiy|a_hour|a_iconfile|a_iconhidden|a_iconnumber|a_icontip|a_index|a_ipaddress1|a_ipaddress2|a_ipaddress3|a_ipaddress4|a_isadmin|a_iscompiled|a_iscritical|a_ispaused|a_issuspended|a_isunicode|a_keydelay|a_language|a_lasterror|a_linefile|a_linenumber|a_loopfield|a_loopfileattrib|a_loopfiledir|a_loopfileext|a_loopfilefullpath|a_loopfilelongpath|a_loopfilename|a_loopfileshortname|a_loopfileshortpath|a_loopfilesize|a_loopfilesizekb|a_loopfilesizemb|a_loopfiletimeaccessed|a_loopfiletimecreated|a_loopfiletimemodified|a_loopreadline|a_loopregkey|a_loopregname|a_loopregsubkey|a_loopregtimemodified|a_loopregtype|a_mday|a_min|a_mm|a_mmm|a_mmmm|a_mon|a_mousedelay|a_msec|a_mydocuments|a_now|a_nowutc|a_numbatchlines|a_ostype|a_osversion|a_priorhotkey|programfiles|a_programfiles|a_programs|a_programscommon|a_screenheight|a_screenwidth|a_scriptdir|a_scriptfullpath|a_scriptname|a_sec|a_space|a_startmenu|a_startmenucommon|a_startup|a_startupcommon|a_stringcasesense|a_tab|a_temp|a_thisfunc|a_thishotkey|a_thislabel|a_thismenu|a_thismenuitem|a_thismenuitempos|a_tickcount|a_timeidle|a_timeidlephysical|a_timesincepriorhotkey|a_timesincethishotkey|a_titlematchmode|a_titlematchmodespeed|a_username|a_wday|a_windelay|a_windir|a_workingdir|a_yday|a_year|a_yweek|a_yyyy|clipboard|clipboardall|comspec|errorlevel)\b/i,builtin:/\b(abs|acos|asc|asin|atan|ceil|chr|class|cos|dllcall|exp|fileexist|Fileopen|floor|il_add|il_create|il_destroy|instr|substr|isfunc|islabel|IsObject|ln|log|lv_add|lv_delete|lv_deletecol|lv_getcount|lv_getnext|lv_gettext|lv_insert|lv_insertcol|lv_modify|lv_modifycol|lv_setimagelist|mod|onmessage|numget|numput|registercallback|regexmatch|regexreplace|round|sin|tan|sqrt|strlen|sb_seticon|sb_setparts|sb_settext|strsplit|tv_add|tv_delete|tv_getchild|tv_getcount|tv_getnext|tv_get|tv_getparent|tv_getprev|tv_getselection|tv_gettext|tv_modify|varsetcapacity|winactive|winexist|__New|__Call|__Get|__Set)\b/i,symbol:/\b(alt|altdown|altup|appskey|backspace|browser_back|browser_favorites|browser_forward|browser_home|browser_refresh|browser_search|browser_stop|bs|capslock|ctrl|ctrlbreak|ctrldown|ctrlup|del|delete|down|end|enter|esc|escape|f1|f10|f11|f12|f13|f14|f15|f16|f17|f18|f19|f2|f20|f21|f22|f23|f24|f3|f4|f5|f6|f7|f8|f9|home|ins|insert|joy1|joy10|joy11|joy12|joy13|joy14|joy15|joy16|joy17|joy18|joy19|joy2|joy20|joy21|joy22|joy23|joy24|joy25|joy26|joy27|joy28|joy29|joy3|joy30|joy31|joy32|joy4|joy5|joy6|joy7|joy8|joy9|joyaxes|joybuttons|joyinfo|joyname|joypov|joyr|joyu|joyv|joyx|joyy|joyz|lalt|launch_app1|launch_app2|launch_mail|launch_media|lbutton|lcontrol|lctrl|left|lshift|lwin|lwindown|lwinup|mbutton|media_next|media_play_pause|media_prev|media_stop|numlock|numpad0|numpad1|numpad2|numpad3|numpad4|numpad5|numpad6|numpad7|numpad8|numpad9|numpadadd|numpadclear|numpaddel|numpaddiv|numpaddot|numpaddown|numpadend|numpadenter|numpadhome|numpadins|numpadleft|numpadmult|numpadpgdn|numpadpgup|numpadright|numpadsub|numpadup|pgdn|pgup|printscreen|ralt|rbutton|rcontrol|rctrl|right|rshift|rwin|rwindown|rwinup|scrolllock|shift|shiftdown|shiftup|space|tab|up|volume_down|volume_mute|volume_up|wheeldown|wheelleft|wheelright|wheelup|xbutton1|xbutton2)\b/i,important:/#\b(AllowSameLineComments|ClipboardTimeout|CommentFlag|ErrorStdOut|EscapeChar|HotkeyInterval|HotkeyModifierTimeout|Hotstring|IfWinActive|IfWinExist|IfWinNotActive|IfWinNotExist|Include|IncludeAgain|InstallKeybdHook|InstallMouseHook|KeyHistory|LTrim|MaxHotkeysPerInterval|MaxMem|MaxThreads|MaxThreadsBuffer|MaxThreadsPerHotkey|NoEnv|NoTrayIcon|Persistent|SingleInstance|UseHook|WinActivateForce)\b/i,keyword:/\b(Abort|AboveNormal|Add|ahk_class|ahk_group|ahk_id|ahk_pid|All|Alnum|Alpha|AltSubmit|AltTab|AltTabAndMenu|AltTabMenu|AltTabMenuDismiss|AlwaysOnTop|AutoSize|Background|BackgroundTrans|BelowNormal|between|BitAnd|BitNot|BitOr|BitShiftLeft|BitShiftRight|BitXOr|Bold|Border|Button|ByRef|Checkbox|Checked|CheckedGray|Choose|ChooseString|Close|Color|ComboBox|Contains|ControlList|Count|Date|DateTime|Days|DDL|Default|DeleteAll|Delimiter|Deref|Destroy|Digit|Disable|Disabled|DropDownList|Edit|Eject|Else|Enable|Enabled|Error|Exist|Expand|ExStyle|FileSystem|First|Flash|Float|FloatFast|Focus|Font|for|global|Grid|Group|GroupBox|GuiClose|GuiContextMenu|GuiDropFiles|GuiEscape|GuiSize|Hdr|Hidden|Hide|High|HKCC|HKCR|HKCU|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_LOCAL_MACHINE|HKEY_USERS|HKLM|HKU|Hours|HScroll|Icon|IconSmall|ID|IDLast|If|IfEqual|IfExist|IfGreater|IfGreaterOrEqual|IfInString|IfLess|IfLessOrEqual|IfMsgBox|IfNotEqual|IfNotExist|IfNotInString|IfWinActive|IfWinExist|IfWinNotActive|IfWinNotExist|Ignore|ImageList|in|Integer|IntegerFast|Interrupt|is|italic|Join|Label|LastFound|LastFoundExist|Limit|Lines|List|ListBox|ListView|local|Lock|Logoff|Low|Lower|Lowercase|MainWindow|Margin|Maximize|MaximizeBox|MaxSize|Minimize|MinimizeBox|MinMax|MinSize|Minutes|MonthCal|Mouse|Move|Multi|NA|No|NoActivate|NoDefault|NoHide|NoIcon|NoMainWindow|norm|Normal|NoSort|NoSortHdr|NoStandard|Not|NoTab|NoTimers|Number|Off|Ok|On|OwnDialogs|Owner|Parse|Password|Picture|Pixel|Pos|Pow|Priority|ProcessName|Radio|Range|Read|ReadOnly|Realtime|Redraw|REG_BINARY|REG_DWORD|REG_EXPAND_SZ|REG_MULTI_SZ|REG_SZ|Region|Relative|Rename|Report|Resize|Restore|Retry|RGB|Screen|Seconds|Section|Serial|SetLabel|ShiftAltTab|Show|Single|Slider|SortDesc|Standard|static|Status|StatusBar|StatusCD|strike|Style|Submit|SysMenu|Tab2|TabStop|Text|Theme|Tile|ToggleCheck|ToggleEnable|ToolWindow|Top|Topmost|TransColor|Transparent|Tray|TreeView|TryAgain|Type|UnCheck|underline|Unicode|Unlock|UpDown|Upper|Uppercase|UseErrorLevel|Vis|VisFirst|Visible|VScroll|Wait|WaitClose|WantCtrlA|WantF2|WantReturn|While|Wrap|Xdigit|xm|xp|xs|Yes|ym|yp|ys)\b/i},function(e){var t={variable:[{pattern:/\$?\(\([\w\W]+?\)\)/,inside:{variable:[{pattern:/(^\$\(\([\w\W]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b-?(?:0x[\dA-Fa-f]+|\d*\.?\d+(?:[Ee]-?\d+)?)\b/,operator:/--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\([^)]+\)|`[^`]+`/,inside:{variable:/^\$\(|^`|\)$|`$/}},/\$(?:[a-z0-9_#\?\*!@]+|\{[^}]+\})/i]};e.languages.bash={shebang:{pattern:/^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,alias:"important"},comment:{pattern:/(^|[^"{\\])#.*/,lookbehind:!0},string:[{pattern:/((?:^|[^<])<<\s*)(?:"|')?(\w+?)(?:"|')?\s*\r?\n(?:[\s\S])*?\r?\n\2/g,lookbehind:!0,greedy:!0,inside:t},{pattern:/(["'])(?:\\\\|\\?[^\\])*?\1/g,greedy:!0,inside:t}],variable:t.variable,"function":{pattern:/(^|\s|;|\||&)(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|\s|;|\||&)/,lookbehind:!0},keyword:{pattern:/(^|\s|;|\||&)(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|\s|;|\||&)/,lookbehind:!0},"boolean":{pattern:/(^|\s|;|\||&)(?:true|false)(?=$|\s|;|\||&)/,lookbehind:!0},operator:/&&?|\|\|?|==?|!=?|<<>|<=?|>=?|=~/,punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];]/};var n=t.variable[1].inside;n["function"]=e.languages.bash["function"],n.keyword=e.languages.bash.keyword,n["boolean"]=e.languages.bash["boolean"],n.operator=e.languages.bash.operator,n.punctuation=e.languages.bash.punctuation}(Prism),Prism.languages.basic={string:/"(?:""|[!#$%&'()*,\/:;<=>?^_ +\-.A-Z\d])*"/i,comment:{pattern:/(?:!|REM\b).+/i,inside:{keyword:/^REM/i}},number:/(?:\b|\B[.-])(?:\d+\.?\d*)(?:E[+-]?\d+)?/i,keyword:/\b(?:AS|BEEP|BLOAD|BSAVE|CALL(?: ABSOLUTE)?|CASE|CHAIN|CHDIR|CLEAR|CLOSE|CLS|COM|COMMON|CONST|DATA|DECLARE|DEF(?: FN| SEG|DBL|INT|LNG|SNG|STR)|DIM|DO|DOUBLE|ELSE|ELSEIF|END|ENVIRON|ERASE|ERROR|EXIT|FIELD|FILES|FOR|FUNCTION|GET|GOSUB|GOTO|IF|INPUT|INTEGER|IOCTL|KEY|KILL|LINE INPUT|LOCATE|LOCK|LONG|LOOP|LSET|MKDIR|NAME|NEXT|OFF|ON(?: COM| ERROR| KEY| TIMER)?|OPEN|OPTION BASE|OUT|POKE|PUT|READ|REDIM|REM|RESTORE|RESUME|RETURN|RMDIR|RSET|RUN|SHARED|SINGLE|SELECT CASE|SHELL|SLEEP|STATIC|STEP|STOP|STRING|SUB|SWAP|SYSTEM|THEN|TIMER|TO|TROFF|TRON|TYPE|UNLOCK|UNTIL|USING|VIEW PRINT|WAIT|WEND|WHILE|WRITE)(?:\$|\b)/i,"function":/\b(?:ABS|ACCESS|ACOS|ANGLE|AREA|ARITHMETIC|ARRAY|ASIN|ASK|AT|ATN|BASE|BEGIN|BREAK|CAUSE|CEIL|CHR|CLIP|COLLATE|COLOR|CON|COS|COSH|COT|CSC|DATE|DATUM|DEBUG|DECIMAL|DEF|DEG|DEGREES|DELETE|DET|DEVICE|DISPLAY|DOT|ELAPSED|EPS|ERASABLE|EXLINE|EXP|EXTERNAL|EXTYPE|FILETYPE|FIXED|FP|GO|GRAPH|HANDLER|IDN|IMAGE|IN|INT|INTERNAL|IP|IS|KEYED|LBOUND|LCASE|LEFT|LEN|LENGTH|LET|LINE|LINES|LOG|LOG10|LOG2|LTRIM|MARGIN|MAT|MAX|MAXNUM|MID|MIN|MISSING|MOD|NATIVE|NUL|NUMERIC|OF|OPTION|ORD|ORGANIZATION|OUTIN|OUTPUT|PI|POINT|POINTER|POINTS|POS|PRINT|PROGRAM|PROMPT|RAD|RADIANS|RANDOMIZE|RECORD|RECSIZE|RECTYPE|RELATIVE|REMAINDER|REPEAT|REST|RETRY|REWRITE|RIGHT|RND|ROUND|RTRIM|SAME|SEC|SELECT|SEQUENTIAL|SET|SETTER|SGN|SIN|SINH|SIZE|SKIP|SQR|STANDARD|STATUS|STR|STREAM|STYLE|TAB|TAN|TANH|TEMPLATE|TEXT|THERE|TIME|TIMEOUT|TRACE|TRANSFORM|TRUNCATE|UBOUND|UCASE|USE|VAL|VARIABLE|VIEWPORT|WHEN|WINDOW|WITH|ZER|ZONEWIDTH)(?:\$|\b)/i,operator:/<[=>]?|>=?|[+\-*\/^=&]|\b(?:AND|EQV|IMP|NOT|OR|XOR)\b/i,punctuation:/[,;:()]/},function(){var e=/%%?[~:\w]+%?|!\S+!/,t={pattern:/\/[a-z?]+(?=[ :]|$):?|-[a-z]\b|--[a-z-]+\b/im,alias:"attr-name",inside:{punctuation:/:/}},n=/"[^"]*"/,a=/(?:\b|-)\d+\b/;Prism.languages.batch={comment:[/^::.*/m,{pattern:/((?:^|[&(])[ \t]*)rem\b(?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0}],label:{pattern:/^:.*/m,alias:"property"},command:[{pattern:/((?:^|[&(])[ \t]*)for(?: ?\/[a-z?](?:[ :](?:"[^"]*"|\S+))?)* \S+ in \([^)]+\) do/im,lookbehind:!0,inside:{keyword:/^for\b|\b(?:in|do)\b/i,string:n,parameter:t,variable:e,number:a,punctuation:/[()',]/}},{pattern:/((?:^|[&(])[ \t]*)if(?: ?\/[a-z?](?:[ :](?:"[^"]*"|\S+))?)* (?:not )?(?:cmdextversion \d+|defined \w+|errorlevel \d+|exist \S+|(?:"[^"]*"|\S+)?(?:==| (?:equ|neq|lss|leq|gtr|geq) )(?:"[^"]*"|\S+))/im,lookbehind:!0,inside:{keyword:/^if\b|\b(?:not|cmdextversion|defined|errorlevel|exist)\b/i,string:n,parameter:t,variable:e,number:a,operator:/\^|==|\b(?:equ|neq|lss|leq|gtr|geq)\b/i}},{pattern:/((?:^|[&()])[ \t]*)else\b/im,lookbehind:!0,inside:{keyword:/^else\b/i}},{pattern:/((?:^|[&(])[ \t]*)set(?: ?\/[a-z](?:[ :](?:"[^"]*"|\S+))?)* (?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0,inside:{keyword:/^set\b/i,string:n,parameter:t,variable:[e,/\w+(?=(?:[*\/%+\-&^|]|<<|>>)?=)/],number:a,operator:/[*\/%+\-&^|]=?|<<=?|>>=?|[!~_=]/,punctuation:/[()',]/}},{pattern:/((?:^|[&(])[ \t]*@?)\w+\b(?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0,inside:{keyword:/^\w+\b/i,string:n,parameter:t,label:{pattern:/(^\s*):\S+/m,lookbehind:!0,alias:"property"},variable:e,number:a,operator:/\^/}}],operator:/[&@]/,punctuation:/[()']/}}(),Prism.languages.c=Prism.languages.extend("clike",{keyword:/\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,operator:/\-[>-]?|\+\+?|!=?|<>?=?|==?|&&?|\|?\||[~^%?*\/]/,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)[ful]*\b/i}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+([^\r\n\\]|\\.|\\(?:\r\n?|\n))*/im,lookbehind:!0,alias:"property",inside:{string:{pattern:/(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/,lookbehind:!0},directive:{pattern:/(#\s*)\b(define|elif|else|endif|error|ifdef|ifndef|if|import|include|line|pragma|undef|using)\b/,lookbehind:!0,alias:"keyword"}}},constant:/\b(__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|stdin|stdout|stderr)\b/}),delete Prism.languages.c["class-name"],delete Prism.languages.c["boolean"],Prism.languages.brainfuck={pointer:{pattern:/<|>/,alias:"keyword"},increment:{pattern:/\+/,alias:"inserted"},decrement:{pattern:/-/,alias:"deleted"},branching:{pattern:/\[|\]/,alias:"important"},operator:/[.,]/,comment:/\S+/},Prism.languages.bro={comment:{pattern:/(^|[^\\$])#.*/,lookbehind:!0,inside:{italic:/\b(TODO|FIXME|XXX)\b/}},string:{pattern:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"boolean":/\b(T|F)\b/,"function":{pattern:/(?:function|hook|event) [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/,inside:{keyword:/^(?:function|hook|event)/}},variable:{pattern:/(?:global|local) [a-zA-Z0-9_]+/i,inside:{keyword:/(?:global|local)/}},builtin:/(@(load(-(sigs|plugin))?|unload|prefixes|ifn?def|else|(end)?if|DIR|FILENAME))|(&?(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column))/,constant:{pattern:/const [a-zA-Z0-9_]+/i,inside:{keyword:/const/}},keyword:/\b(break|next|continue|alarm|using|of|add|delete|export|print|return|schedule|when|timeout|addr|any|bool|count|double|enum|file|int|interval|pattern|opaque|port|record|set|string|subnet|table|time|vector|for|if|else|in|module|function)\b/,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,punctuation:/[{}[\];(),.:]/},Prism.languages.bison=Prism.languages.extend("c",{}),Prism.languages.insertBefore("bison","comment",{bison:{pattern:/^[\s\S]*?%%[\s\S]*?%%/,inside:{c:{pattern:/%\{[\s\S]*?%\}|\{(?:\{[^}]*\}|[^{}])*\}/,inside:{delimiter:{pattern:/^%?\{|%?\}$/,alias:"punctuation"},"bison-variable":{pattern:/[$@](?:<[^\s>]+>)?[\w$]+/,alias:"variable",inside:{punctuation:/<|>/}},rest:Prism.languages.c}},comment:Prism.languages.c.comment,string:Prism.languages.c.string,property:/\S+(?=:)/,keyword:/%\w+/,number:{pattern:/(^|[^@])\b(?:0x[\da-f]+|\d+)/i,lookbehind:!0},punctuation:/%[%?]|[|:;\[\]<>]/}}}),Prism.languages.csharp=Prism.languages.extend("clike",{keyword:/\b(abstract|as|async|await|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while|add|alias|ascending|async|await|descending|dynamic|from|get|global|group|into|join|let|orderby|partial|remove|select|set|value|var|where|yield)\b/,string:[/@("|')(\1\1|\\\1|\\?(?!\1)[\s\S])*\1/,/("|')(\\?.)*?\1/],number:/\b-?(0x[\da-f]+|\d*\.?\d+f?)\b/i}),Prism.languages.insertBefore("csharp","keyword",{"generic-method":{pattern:/[a-z0-9_]+\s*<[^>\r\n]+?>\s*(?=\()/i,alias:"function",inside:{keyword:Prism.languages.csharp.keyword,punctuation:/[<>(),.:]/}},preprocessor:{pattern:/(^\s*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(\s*#)\b(define|elif|else|endif|endregion|error|if|line|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}}),Prism.languages.cpp=Prism.languages.extend("c",{keyword:/\b(alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,"boolean":/\b(true|false)\b/,operator:/[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|:{1,2}|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\/|\b(and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/}),Prism.languages.insertBefore("cpp","keyword",{"class-name":{pattern:/(class\s+)[a-z0-9_]+/i,lookbehind:!0}}),function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\?[^\\])*?'/,greedy:!0},{pattern:/"(?:\\?[^\\])*?"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\?[\s\S])*?`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},rest:e.languages.javascript}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"]}(Prism),function(e){e.languages.ruby=e.languages.extend("clike",{comment:/#(?!\{[^\r\n]*?\}).*/,keyword:/\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/});var t={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:e.util.clone(e.languages.ruby)}};e.languages.insertBefore("ruby","keyword",{regex:[{pattern:/%r([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1[gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/,inside:{interpolation:t}},{pattern:/%r<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/,inside:{interpolation:t}},{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}],variable:/[@$]+[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/,symbol:/:[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/}),e.languages.insertBefore("ruby","number",{builtin:/\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z][a-zA-Z_0-9]*(?:[?!]|\b)/}),e.languages.ruby.string=[{pattern:/%[qQiIwWxs]?([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\((?:[^()\\]|\\[\s\S])*\)/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\[(?:[^\[\]\\]|\\[\s\S])*\]/,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?<(?:[^<>\\]|\\[\s\S])*>/,inside:{interpolation:t}},{pattern:/("|')(#\{[^}]+\}|\\(?:\r?\n|\r)|\\?.)*?\1/,inside:{interpolation:t}}]}(Prism),Prism.languages.css.selector={pattern:/[^\{\}\s][^\{\}]*(?=\s*\{)/,inside:{"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+(?:\(.*\))?/,"class":/\.[-:\.\w]+/,id:/#[-:\.\w]+/,attribute:/\[[^\]]+\]/}},Prism.languages.insertBefore("css","function",{hexcode:/#[\da-f]{3,6}/i,entity:/\\[\da-f]{1,8}/i,number:/[\d%\.]+/}),Prism.languages.d=Prism.languages.extend("clike",{string:[/\b[rx]"(\\.|[^\\"])*"[cwd]?/,/\bq"(?:\[[\s\S]*?\]|\([\s\S]*?\)|<[\s\S]*?>|\{[\s\S]*?\})"/,/\bq"([_a-zA-Z][_a-zA-Z\d]*)(?:\r?\n|\r)[\s\S]*?(?:\r?\n|\r)\1"/,/\bq"(.)[\s\S]*?\1"/,/'(?:\\'|\\?[^']+)'/,/(["`])(\\.|(?!\1)[^\\])*\1[cwd]?/],number:[/\b0x\.?[a-f\d_]+(?:(?!\.\.)\.[a-f\d_]*)?(?:p[+-]?[a-f\d_]+)?[ulfi]*/i,{pattern:/((?:\.\.)?)(?:\b0b\.?|\b|\.)\d[\d_]*(?:(?!\.\.)\.[\d_]*)?(?:e[+-]?\d[\d_]*)?[ulfi]*/i,lookbehind:!0}],keyword:/\$|\b(?:abstract|alias|align|asm|assert|auto|body|bool|break|byte|case|cast|catch|cdouble|cent|cfloat|char|class|const|continue|creal|dchar|debug|default|delegate|delete|deprecated|do|double|else|enum|export|extern|false|final|finally|float|for|foreach|foreach_reverse|function|goto|idouble|if|ifloat|immutable|import|inout|int|interface|invariant|ireal|lazy|long|macro|mixin|module|new|nothrow|null|out|override|package|pragma|private|protected|public|pure|real|ref|return|scope|shared|short|static|struct|super|switch|synchronized|template|this|throw|true|try|typedef|typeid|typeof|ubyte|ucent|uint|ulong|union|unittest|ushort|version|void|volatile|wchar|while|with|__(?:(?:FILE|MODULE|LINE|FUNCTION|PRETTY_FUNCTION|DATE|EOF|TIME|TIMESTAMP|VENDOR|VERSION)__|gshared|traits|vector|parameters)|string|wstring|dstring|size_t|ptrdiff_t)\b/,operator:/\|[|=]?|&[&=]?|\+[+=]?|-[-=]?|\.?\.\.|=[>=]?|!(?:i[ns]\b|<>?=?|>=?|=)?|\bi[ns]\b|(?:<[<>]?|>>?>?|\^\^|[*\/%^~])=?/}),Prism.languages.d.comment=[/^\s*#!.+/,{pattern:/(^|[^\\])\/\+(?:\/\+[\w\W]*?\+\/|[\w\W])*?\+\//,lookbehind:!0}].concat(Prism.languages.d.comment),Prism.languages.insertBefore("d","comment",{"token-string":{pattern:/\bq\{(?:|\{[^}]*\}|[^}])*\}/,alias:"string"}}),Prism.languages.insertBefore("d","keyword",{property:/\B@\w*/}), +Prism.languages.insertBefore("d","function",{register:{pattern:/\b(?:[ABCD][LHX]|E[ABCD]X|E?(?:BP|SP|DI|SI)|[ECSDGF]S|CR[0234]|DR[012367]|TR[3-7]|X?MM[0-7]|R[ABCD]X|[BS]PL|R[BS]P|[DS]IL|R[DS]I|R(?:[89]|1[0-5])[BWD]?|XMM(?:[89]|1[0-5])|YMM(?:1[0-5]|\d))\b|\bST(?:\([0-7]\)|\b)/,alias:"variable"}}),Prism.languages.dart=Prism.languages.extend("clike",{string:[/r?("""|''')[\s\S]*?\1/,/r?("|')(\\?.)*?\1/],keyword:[/\b(?:async|sync|yield)\*/,/\b(?:abstract|assert|async|await|break|case|catch|class|const|continue|default|deferred|do|dynamic|else|enum|export|external|extends|factory|final|finally|for|get|if|implements|import|in|library|new|null|operator|part|rethrow|return|set|static|super|switch|this|throw|try|typedef|var|void|while|with|yield)\b/],operator:/\bis!|\b(?:as|is)\b|\+\+|--|&&|\|\||<<=?|>>=?|~(?:\/=?)?|[+\-*\/%&^|=!<>]=?|\?/}),Prism.languages.insertBefore("dart","function",{metadata:{pattern:/@\w+/,alias:"symbol"}}),Prism.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d+.*$/m],deleted:/^[-<].*$/m,inserted:/^[+>].*$/m,diff:{pattern:/^!(?!!).+$/m,alias:"important"}},Prism.languages.docker={keyword:{pattern:/(^\s*)(?:ONBUILD|FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|COPY|VOLUME|USER|WORKDIR|CMD|LABEL|ENTRYPOINT)(?=\s)/im,lookbehind:!0},string:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*?\1/,comment:/#.*/,punctuation:/---|\.\.\.|[:[\]{}\-,|>?]/},Prism.languages.eiffel={string:[/"([^[]*)\[[\s\S]+?\]\1"/,/"([^{]*)\{[\s\S]+?\}\1"/,/"(?:%\s+%|%"|.)*?"/],comment:/--.*/,"char":/'(?:%'|.)+?'/,keyword:/\b(?:across|agent|alias|all|and|attached|as|assign|attribute|check|class|convert|create|Current|debug|deferred|detachable|do|else|elseif|end|ensure|expanded|export|external|feature|from|frozen|if|implies|inherit|inspect|invariant|like|local|loop|not|note|obsolete|old|once|or|Precursor|redefine|rename|require|rescue|Result|retry|select|separate|some|then|undefine|until|variant|Void|when|xor)\b/i,"boolean":/\b(?:True|False)\b/i,number:[/\b0[xcb][\da-f](?:_*[\da-f])*\b/i,/(?:\d(?:_*\d)*)?\.(?:(?:\d(?:_*\d)*)?[eE][+-]?)?\d(?:_*\d)*|\d(?:_*\d)*\.?/],punctuation:/:=|<<|>>|\(\||\|\)|->|\.(?=\w)|[{}[\];(),:?]/,operator:/\\\\|\|\.\.\||\.\.|\/[~\/=]?|[><]=?|[-+*^=~]/},Prism.languages.elixir={comment:{pattern:/(^|[^#])#(?![{#]).*/m,lookbehind:!0},regex:/~[rR](?:("""|'''|[\/|"'])(?:\\.|(?!\1)[^\\])+\1|\((?:\\\)|[^)])+\)|\[(?:\\\]|[^\]])+\]|\{(?:\\\}|[^}])+\}|<(?:\\>|[^>])+>)[uismxfr]*/,string:[{pattern:/~[cCsSwW](?:("""|'''|[\/|"'])(?:\\.|(?!\1)[^\\])+\1|\((?:\\\)|[^)])+\)|\[(?:\\\]|[^\]])+\]|\{(?:\\\}|#\{[^}]+\}|[^}])+\}|<(?:\\>|[^>])+>)[csa]?/,inside:{}},{pattern:/("""|''')[\s\S]*?\1/,inside:{}},{pattern:/("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/,inside:{}}],atom:{pattern:/(^|[^:]):\w+/,lookbehind:!0,alias:"symbol"},"attr-name":/\w+:(?!:)/,capture:{pattern:/(^|[^&])&(?:[^&\s\d()][^\s()]*|(?=\())/,lookbehind:!0,alias:"function"},argument:{pattern:/(^|[^&])&\d+/,lookbehind:!0,alias:"variable"},attribute:{pattern:/@[\S]+/,alias:"variable"},number:/\b(?:0[box][a-f\d_]+|\d[\d_]*)(?:\.[\d_]+)?(?:e[+-]?[\d_]+)?\b/i,keyword:/\b(?:after|alias|and|case|catch|cond|def(?:callback|exception|impl|module|p|protocol|struct)?|do|else|end|fn|for|if|import|not|or|require|rescue|try|unless|use|when)\b/,"boolean":/\b(?:true|false|nil)\b/,operator:[/\bin\b|&&?|\|[|>]?|\\\\|::|\.\.\.?|\+\+?|-[->]?|<[-=>]|>=|!==?|\B!|=(?:==?|[>~])?|[*\/^]/,{pattern:/([^<])<(?!<)/,lookbehind:!0},{pattern:/([^>])>(?!>)/,lookbehind:!0}],punctuation:/<<|>>|[.,%\[\]{}()]/},Prism.languages.elixir.string.forEach(function(e){e.inside={interpolation:{pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"},rest:Prism.util.clone(Prism.languages.elixir)}}}}),Prism.languages.erlang={comment:/%.+/,string:/"(?:\\?.)*?"/,"quoted-function":{pattern:/'(?:\\.|[^'\\])+'(?=\()/,alias:"function"},"quoted-atom":{pattern:/'(?:\\.|[^'\\])+'/,alias:"atom"},"boolean":/\b(?:true|false)\b/,keyword:/\b(?:fun|when|case|of|end|if|receive|after|try|catch)\b/,number:[/\$\\?./,/\d+#[a-z0-9]+/i,/(?:\b|-)\d*\.?\d+([Ee][+-]?\d+)?\b/],"function":/\b[a-z][\w@]*(?=\()/,variable:{pattern:/(^|[^@])(?:\b|\?)[A-Z_][\w@]*/,lookbehind:!0},operator:[/[=\/<>:]=|=[:\/]=|\+\+?|--?|[=*\/!]|\b(?:bnot|div|rem|band|bor|bxor|bsl|bsr|not|and|or|xor|orelse|andalso)\b/,{pattern:/(^|[^<])<(?!<)/,lookbehind:!0},{pattern:/(^|[^>])>(?!>)/,lookbehind:!0}],atom:/\b[a-z][\w@]*/,punctuation:/[()[\]{}:;,.#|]|<<|>>/},Prism.languages.fsharp=Prism.languages.extend("clike",{comment:[{pattern:/(^|[^\\])\(\*[\w\W]*?\*\)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],keyword:/\b(?:let|return|use|yield)(?:!\B|\b)|\b(abstract|and|as|assert|base|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|global|if|in|inherit|inline|interface|internal|lazy|match|member|module|mutable|namespace|new|not|null|of|open|or|override|private|public|rec|select|static|struct|then|to|true|try|type|upcast|val|void|when|while|with|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|include|method|mixin|object|parallel|process|protected|pure|sealed|tailcall|trait|virtual|volatile)\b/,string:/(?:"""[\s\S]*?"""|@"(?:""|[^"])*"|("|')(?:\\\1|\\?(?!\1)[\s\S])*\1)B?/,number:[/\b-?0x[\da-fA-F]+(un|lf|LF)?\b/,/\b-?0b[01]+(y|uy)?\b/,/\b-?(\d*\.?\d+|\d+\.)([fFmM]|[eE][+-]?\d+)?\b/,/\b-?\d+(y|uy|s|us|l|u|ul|L|UL|I)?\b/]}),Prism.languages.insertBefore("fsharp","keyword",{preprocessor:{pattern:/^[^\r\n\S]*#.*/m,alias:"property",inside:{directive:{pattern:/(\s*#)\b(else|endif|if|light|line|nowarn)\b/,lookbehind:!0,alias:"keyword"}}}}),Prism.languages.fortran={"quoted-number":{pattern:/[BOZ](['"])[A-F0-9]+\1/i,alias:"number"},string:{pattern:/(?:\w+_)?(['"])(?:\1\1|&(?:\r\n?|\n)(?:\s*!.+(?:\r\n?|\n))?|(?!\1).)*(?:\1|&)/,inside:{comment:{pattern:/(&(?:\r\n?|\n)\s*)!.*/,lookbehind:!0}}},comment:/!.*/,"boolean":/\.(?:TRUE|FALSE)\.(?:_\w+)?/i,number:/(?:\b|[+-])(?:\d+(?:\.\d*)?|\.\d+)(?:[ED][+-]?\d+)?(?:_\w+)?/i,keyword:[/\b(?:INTEGER|REAL|DOUBLE ?PRECISION|COMPLEX|CHARACTER|LOGICAL)\b/i,/\b(?:END ?)?(?:BLOCK ?DATA|DO|FILE|FORALL|FUNCTION|IF|INTERFACE|MODULE(?! PROCEDURE)|PROGRAM|SELECT|SUBROUTINE|TYPE|WHERE)\b/i,/\b(?:ALLOCATABLE|ALLOCATE|BACKSPACE|CALL|CASE|CLOSE|COMMON|CONTAINS|CONTINUE|CYCLE|DATA|DEALLOCATE|DIMENSION|DO|END|EQUIVALENCE|EXIT|EXTERNAL|FORMAT|GO ?TO|IMPLICIT(?: NONE)?|INQUIRE|INTENT|INTRINSIC|MODULE PROCEDURE|NAMELIST|NULLIFY|OPEN|OPTIONAL|PARAMETER|POINTER|PRINT|PRIVATE|PUBLIC|READ|RETURN|REWIND|SAVE|SELECT|STOP|TARGET|WHILE|WRITE)\b/i,/\b(?:ASSIGNMENT|DEFAULT|ELEMENTAL|ELSE|ELSEWHERE|ELSEIF|ENTRY|IN|INCLUDE|INOUT|KIND|NULL|ONLY|OPERATOR|OUT|PURE|RECURSIVE|RESULT|SEQUENCE|STAT|THEN|USE)\b/i],operator:[/\*\*|\/\/|=>|[=\/]=|[<>]=?|::|[+\-*=%]|\.(?:EQ|NE|LT|LE|GT|GE|NOT|AND|OR|EQV|NEQV)\.|\.[A-Z]+\./i,{pattern:/(^|(?!\().)\/(?!\))/,lookbehind:!0}],punctuation:/\(\/|\/\)|[(),;:&]/},Prism.languages.gherkin={pystring:{pattern:/("""|''')[\s\S]+?\1/,alias:"string"},comment:{pattern:/((^|\r?\n|\r)[ \t]*)#.*/,lookbehind:!0},tag:{pattern:/((^|\r?\n|\r)[ \t]*)@\S*/,lookbehind:!0},feature:{pattern:/((^|\r?\n|\r)[ \t]*)(Ability|Ahoy matey!|Arwedd|Aspekt|Besigheid Behoefte|Business Need|Caracteristica|Caracter\xedstica|Egenskab|Egenskap|Eiginleiki|Feature|F\u012b\u010da|Fitur|Fonctionnalit\xe9|Fonksyonalite|Funcionalidade|Funcionalitat|Functionalitate|Func\u0163ionalitate|Func\u021bionalitate|Functionaliteit|Fungsi|Funkcia|Funkcija|Funkcionalit\u0101te|Funkcionalnost|Funkcja|Funksie|Funktionalit\xe4t|Funktionalit\xe9it|Funzionalit\xe0|Hwaet|Hw\xe6t|Jellemz\u0151|Karakteristik|laH|Lastnost|Mak|Mogucnost|Mogu\u0107nost|Moznosti|Mo\u017enosti|OH HAI|Omadus|Ominaisuus|Osobina|\xd6zellik|perbogh|poQbogh malja'|Potrzeba biznesowa|Po\u017eadavek|Po\u017eiadavka|Pretty much|Qap|Qu'meH 'ut|Savyb\u0117|T\xednh n\u0103ng|Trajto|Vermo\xeb|Vlastnos\u0165|W\u0142a\u015bciwo\u015b\u0107|Zna\u010dilnost|\u0394\u03c5\u03bd\u03b1\u03c4\u03cc\u03c4\u03b7\u03c4\u03b1|\u039b\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1|\u041c\u043e\u0433\u0443\u045b\u043d\u043e\u0441\u0442|\u041c\u04e9\u043c\u043a\u0438\u043d\u043b\u0435\u043a|\u041e\u0441\u043e\u0431\u0438\u043d\u0430|\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e|\u04ae\u0437\u0435\u043d\u0447\u04d9\u043b\u0435\u043a\u043b\u0435\u043b\u0435\u043a|\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b|\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u043d\u043e\u0441\u0442|\u0424\u0443\u043d\u043a\u0446\u0438\u044f|\u0424\u0443\u043d\u043a\u0446\u0456\u043e\u043d\u0430\u043b|\u05ea\u05db\u05d5\u05e0\u05d4|\u062e\u0627\u0635\u064a\u0629|\u062e\u0635\u0648\u0635\u06cc\u062a|\u0635\u0644\u0627\u062d\u06cc\u062a|\u06a9\u0627\u0631\u0648\u0628\u0627\u0631 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a|\u0648\u0650\u06cc\u0698\u06af\u06cc|\u0930\u0942\u092a \u0932\u0947\u0916|\u0a16\u0a3e\u0a38\u0a40\u0a05\u0a24|\u0a28\u0a15\u0a36 \u0a28\u0a41\u0a39\u0a3e\u0a30|\u0a2e\u0a41\u0a39\u0a3e\u0a02\u0a26\u0a30\u0a3e|\u0c17\u0c41\u0c23\u0c2e\u0c41|\u0cb9\u0cc6\u0c9a\u0ccd\u0c9a\u0cb3|\u0e04\u0e27\u0e32\u0e21\u0e15\u0e49\u0e2d\u0e07\u0e01\u0e32\u0e23\u0e17\u0e32\u0e07\u0e18\u0e38\u0e23\u0e01\u0e34\u0e08|\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e32\u0e21\u0e32\u0e23\u0e16|\u0e42\u0e04\u0e23\u0e07\u0e2b\u0e25\u0e31\u0e01|\uae30\ub2a5|\u30d5\u30a3\u30fc\u30c1\u30e3|\u529f\u80fd|\u6a5f\u80fd):([^:]+(?:\r?\n|\r|$))*/,lookbehind:!0,inside:{important:{pattern:/(:)[^\r\n]+/,lookbehind:!0},keyword:/[^:\r\n]+:/}},scenario:{pattern:/((^|\r?\n|\r)[ \t]*)(Abstract Scenario|Abstrakt Scenario|Achtergrond|Aer|\xc6r|Agtergrond|All y'all|Antecedentes|Antecedents|Atbur\xf0ar\xe1s|Atbur\xf0ar\xe1sir|Awww, look mate|B4|Background|Baggrund|Bakgrund|Bakgrunn|Bakgrunnur|Beispiele|Beispiller|B\u1ed1i c\u1ea3nh|Cefndir|Cenario|Cen\xe1rio|Cenario de Fundo|Cen\xe1rio de Fundo|Cenarios|Cen\xe1rios|Contesto|Context|Contexte|Contexto|Conto|Contoh|Contone|D\xe6mi|Dasar|Dead men tell no tales|Delineacao do Cenario|Delinea\xe7\xe3o do Cen\xe1rio|Dis is what went down|D\u1eef li\u1ec7u|Dyagram senaryo|Dyagram Senaryo|Egzanp|Ejemplos|Eksempler|Ekzemploj|Enghreifftiau|Esbozo do escenario|Escenari|Escenario|Esempi|Esquema de l'escenari|Esquema del escenario|Esquema do Cenario|Esquema do Cen\xe1rio|Examples|EXAMPLZ|Exempel|Exemple|Exemples|Exemplos|First off|Fono|Forgat\xf3k\xf6nyv|Forgat\xf3k\xf6nyv v\xe1zlat|Fundo|Ge\xe7mi\u015f|ghantoH|Grundlage|Hannergrond|H\xe1tt\xe9r|Heave to|Istorik|Juhtumid|Keadaan|Khung k\u1ecbch b\u1ea3n|Khung t\xecnh hu\u1ed1ng|K\u1ecbch b\u1ea3n|Koncept|Konsep skenario|Kont\xe8ks|Kontekst|Kontekstas|Konteksts|Kontext|Konturo de la scenaro|Latar Belakang|lut|lut chovnatlh|lutmey|L\xfdsing Atbur\xf0ar\xe1sar|L\xfdsing D\xe6ma|Menggariskan Senario|MISHUN|MISHUN SRSLY|mo'|N\xe1\u010drt Scen\xe1ra|N\xe1\u010drt Sc\xe9n\xe1\u0159e|N\xe1\u010drt Scen\xe1ru|Oris scenarija|\xd6rnekler|Osnova|Osnova Scen\xe1ra|Osnova sc\xe9n\xe1\u0159e|Osnutek|Ozadje|Paraugs|Pavyzd\u017eiai|P\xe9ld\xe1k|Piem\u0113ri|Plan du sc\xe9nario|Plan du Sc\xe9nario|Plan senaryo|Plan Senaryo|Plang vum Szenario|Pozad\xed|Pozadie|Pozadina|Pr\xedklady|P\u0159\xedklady|Primer|Primeri|Primjeri|Przyk\u0142ady|Raamstsenaarium|Reckon it's like|Rerefons|Scen\xe1r|Sc\xe9n\xe1\u0159|Scenarie|Scenarij|Scenarijai|Scenarijaus \u0161ablonas|Scenariji|Scen\u0101rijs|Scen\u0101rijs p\u0113c parauga|Scenarijus|Scenario|Sc\xe9nario|Scenario Amlinellol|Scenario Outline|Scenario Template|Scenariomal|Scenariomall|Scenarios|Scenariu|Scenariusz|Scenaro|Schema dello scenario|Se \xf0e|Se the|Se \xfee|Senario|Senaryo|Senaryo deskripsyon|Senaryo Deskripsyon|Senaryo tasla\u011f\u0131|Shiver me timbers|Situ\u0101cija|Situai|Situasie|Situasie Uiteensetting|Skenario|Skenario konsep|Skica|Structura scenariu|Structur\u0103 scenariu|Struktura scenarija|Stsenaarium|Swa|Swa hwaer swa|Swa hw\xe6r swa|Szablon scenariusza|Szenario|Szenariogrundriss|Tapaukset|Tapaus|Tapausaihio|Taust|Tausta|Template Keadaan|Template Senario|Template Situai|The thing of it is|T\xecnh hu\u1ed1ng|Variantai|Voorbeelde|Voorbeelden|Wharrimean is|Yo\-ho\-ho|You'll wanna|Za\u0142o\u017cenia|\u03a0\u03b1\u03c1\u03b1\u03b4\u03b5\u03af\u03b3\u03bc\u03b1\u03c4\u03b1|\u03a0\u03b5\u03c1\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae \u03a3\u03b5\u03bd\u03b1\u03c1\u03af\u03bf\u03c5|\u03a3\u03b5\u03bd\u03ac\u03c1\u03b9\u03b1|\u03a3\u03b5\u03bd\u03ac\u03c1\u03b9\u03bf|\u03a5\u03c0\u03cc\u03b2\u03b1\u03b8\u03c1\u03bf|\u041a\u0435\u0440\u0435\u0448|\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442|\u041a\u043e\u043d\u0446\u0435\u043f\u0442|\u041c\u0438\u0441\u0430\u043b\u043b\u0430\u0440|\u041c\u0438\u0441\u043e\u043b\u043b\u0430\u0440|\u041e\u0441\u043d\u043e\u0432\u0430|\u041f\u0435\u0440\u0435\u0434\u0443\u043c\u043e\u0432\u0430|\u041f\u043e\u0437\u0430\u0434\u0438\u043d\u0430|\u041f\u0440\u0435\u0434\u0438\u0441\u0442\u043e\u0440\u0438\u044f|\u041f\u0440\u0435\u0434\u044b\u0441\u0442\u043e\u0440\u0438\u044f|\u041f\u0440\u0438\u043a\u043b\u0430\u0434\u0438|\u041f\u0440\u0438\u043c\u0435\u0440|\u041f\u0440\u0438\u043c\u0435\u0440\u0438|\u041f\u0440\u0438\u043c\u0435\u0440\u044b|\u0420\u0430\u043c\u043a\u0430 \u043d\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439|\u0421\u043a\u0438\u0446\u0430|\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0458\u0430|\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f|\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0456\u044e|\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439|\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u0441\u0438|\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439\u043d\u044b\u04a3 \u0442\u04e9\u0437\u0435\u043b\u0435\u0448\u0435|\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0458\u0438|\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u043e|\u0421\u0446\u0435\u043d\u0430\u0440\u0456\u0439|\u0422\u0430\u0440\u0438\u0445|\u04ae\u0440\u043d\u04d9\u043a\u043b\u04d9\u0440|\u05d3\u05d5\u05d2\u05de\u05d0\u05d5\u05ea|\u05e8\u05e7\u05e2|\u05ea\u05d1\u05e0\u05d9\u05ea \u05ea\u05e8\u05d7\u05d9\u05e9|\u05ea\u05e8\u05d7\u05d9\u05e9|\u0627\u0644\u062e\u0644\u0641\u064a\u0629|\u0627\u0644\u06af\u0648\u06cc \u0633\u0646\u0627\u0631\u06cc\u0648|\u0627\u0645\u062b\u0644\u0629|\u067e\u0633 \u0645\u0646\u0638\u0631|\u0632\u0645\u06cc\u0646\u0647|\u0633\u0646\u0627\u0631\u06cc\u0648|\u0633\u064a\u0646\u0627\u0631\u064a\u0648|\u0633\u064a\u0646\u0627\u0631\u064a\u0648 \u0645\u062e\u0637\u0637|\u0645\u062b\u0627\u0644\u06cc\u06ba|\u0645\u0646\u0638\u0631 \u0646\u0627\u0645\u06d2 \u06a9\u0627 \u062e\u0627\u06a9\u06c1|\u0645\u0646\u0638\u0631\u0646\u0627\u0645\u06c1|\u0646\u0645\u0648\u0646\u0647 \u0647\u0627|\u0909\u0926\u093e\u0939\u0930\u0923|\u092a\u0930\u093f\u0926\u0943\u0936\u094d\u092f|\u092a\u0930\u093f\u0926\u0943\u0936\u094d\u092f \u0930\u0942\u092a\u0930\u0947\u0916\u093e|\u092a\u0943\u0937\u094d\u0920\u092d\u0942\u092e\u093f|\u0a09\u0a26\u0a3e\u0a39\u0a30\u0a28\u0a3e\u0a02|\u0a2a\u0a1f\u0a15\u0a25\u0a3e|\u0a2a\u0a1f\u0a15\u0a25\u0a3e \u0a22\u0a3e\u0a02\u0a1a\u0a3e|\u0a2a\u0a1f\u0a15\u0a25\u0a3e \u0a30\u0a42\u0a2a \u0a30\u0a47\u0a16\u0a3e|\u0a2a\u0a3f\u0a1b\u0a4b\u0a15\u0a5c|\u0c09\u0c26\u0c3e\u0c39\u0c30\u0c23\u0c32\u0c41|\u0c15\u0c25\u0c28\u0c02|\u0c28\u0c47\u0c2a\u0c25\u0c4d\u0c2f\u0c02|\u0c38\u0c28\u0c4d\u0c28\u0c3f\u0c35\u0c47\u0c36\u0c02|\u0c89\u0ca6\u0cbe\u0cb9\u0cb0\u0ca3\u0cc6\u0c97\u0cb3\u0cc1|\u0c95\u0ca5\u0cbe\u0cb8\u0cbe\u0cb0\u0cbe\u0c82\u0cb6|\u0cb5\u0cbf\u0cb5\u0cb0\u0ca3\u0cc6|\u0cb9\u0cbf\u0ca8\u0ccd\u0ca8\u0cc6\u0cb2\u0cc6|\u0e42\u0e04\u0e23\u0e07\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e02\u0e2d\u0e07\u0e40\u0e2b\u0e15\u0e38\u0e01\u0e32\u0e23\u0e13\u0e4c|\u0e0a\u0e38\u0e14\u0e02\u0e2d\u0e07\u0e15\u0e31\u0e27\u0e2d\u0e22\u0e48\u0e32\u0e07|\u0e0a\u0e38\u0e14\u0e02\u0e2d\u0e07\u0e40\u0e2b\u0e15\u0e38\u0e01\u0e32\u0e23\u0e13\u0e4c|\u0e41\u0e19\u0e27\u0e04\u0e34\u0e14|\u0e2a\u0e23\u0e38\u0e1b\u0e40\u0e2b\u0e15\u0e38\u0e01\u0e32\u0e23\u0e13\u0e4c|\u0e40\u0e2b\u0e15\u0e38\u0e01\u0e32\u0e23\u0e13\u0e4c|\ubc30\uacbd|\uc2dc\ub098\ub9ac\uc624|\uc2dc\ub098\ub9ac\uc624 \uac1c\uc694|\uc608|\u30b5\u30f3\u30d7\u30eb|\u30b7\u30ca\u30ea\u30aa|\u30b7\u30ca\u30ea\u30aa\u30a2\u30a6\u30c8\u30e9\u30a4\u30f3|\u30b7\u30ca\u30ea\u30aa\u30c6\u30f3\u30d7\u30ec|\u30b7\u30ca\u30ea\u30aa\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8|\u30c6\u30f3\u30d7\u30ec|\u4f8b|\u4f8b\u5b50|\u5267\u672c|\u5267\u672c\u5927\u7eb2|\u5287\u672c|\u5287\u672c\u5927\u7db1|\u573a\u666f|\u573a\u666f\u5927\u7eb2|\u5834\u666f|\u5834\u666f\u5927\u7db1|\u80cc\u666f):[^:\r\n]*/,lookbehind:!0,inside:{important:{pattern:/(:)[^\r\n]*/,lookbehind:!0},keyword:/[^:\r\n]+:/}},"table-body":{pattern:/((?:\r?\n|\r)[ \t]*\|.+\|[^\r\n]*)+/,lookbehind:!0,inside:{outline:{pattern:/<[^>]+?>/,alias:"variable"},td:{pattern:/\s*[^\s|][^|]*/,alias:"string"},punctuation:/\|/}},"table-head":{pattern:/((?:\r?\n|\r)[ \t]*\|.+\|[^\r\n]*)/,inside:{th:{pattern:/\s*[^\s|][^|]*/,alias:"variable"},punctuation:/\|/}},atrule:{pattern:/((?:\r?\n|\r)[ \t]+)('ach|'a|'ej|7|a|A tak\xe9|A taktie\u017e|A tie\u017e|A z\xe1rove\u0148|Aber|Ac|Adott|Akkor|Ak|Aleshores|Ale|Ali|Allora|Alors|Als|Ama|Amennyiben|Amikor|Ampak|an|AN|Ananging|And y'all|And|Angenommen|Anrhegedig a|An|Apabila|At\xe8s|Atesa|Atunci|Avast!|Aye|A|awer|Bagi|Banjur|Bet|Bi\u1ebft|Blimey!|Buh|But at the end of the day I reckon|But y'all|But|BUT|Cal|C\xe2nd|Cando|Cand|Ce|Cuando|\u010ce|\xd0a \xf0e|\xd0a|Dadas|Dada|Dados|Dado|DaH ghu' bejlu'|dann|Dann|Dano|Dan|Dar|Dat fiind|Data|Date fiind|Date|Dati fiind|Dati|Da\u0163i fiind|Da\u021bi fiind|Dato|DEN|Den youse gotta|Dengan|De|Diberi|Diyelim ki|Donada|Donat|Donita\u0135o|Do|Dun|Duota|\xd0urh|Eeldades|Ef|E\u011fer ki|Entao|Ent\xe3o|Ent\xf3n|Entonces|En|Epi|E|\xc9s|Etant donn\xe9e|Etant donn\xe9|Et|\xc9tant donn\xe9es|\xc9tant donn\xe9e|\xc9tant donn\xe9|Etant donn\xe9es|Etant donn\xe9s|\xc9tant donn\xe9s|Fakat|Gangway!|Gdy|Gegeben seien|Gegeben sei|Gegeven|Gegewe|ghu' noblu'|Gitt|Given y'all|Given|Givet|Givun|Ha|Cho|I CAN HAZ|In|Ir|It's just unbelievable|I|Ja|Je\u015bli|Je\u017celi|Kadar|Kada|Kad|Kai|Kaj|Kdy\u017e|Ke\u010f|Kemudian|Ketika|Khi|Kiedy|Ko|Kuid|Kui|Kun|Lan|latlh|Le sa a|Let go and haul|Le|L\xe8 sa a|L\xe8|Logo|Lorsqu'<|Lorsque|m\xe4|Maar|Mais|Maj\u0105c|Majd|Maka|Manawa|Mas|Ma|Menawa|Men|Mutta|Nalikaning|Nalika|Nanging|N\xe5r|N\xe4r|Nato|Nh\u01b0ng|Niin|Njuk|O zaman|Og|Och|Oletetaan|Onda|Ond|Oraz|Pak|Pero|Per\xf2|Podano|Pokia\u013e|Pokud|Potem|Potom|Privzeto|Pryd|qaSDI'|Quando|Quand|Quan|S\xe5|Sed|Se|Siis|Sipoze ke|Sipoze Ke|Sipoze|Si|\u015ei|\u0218i|Soit|Stel|Tada|Tad|Takrat|Tak|Tapi|Ter|Tetapi|Tha the|Tha|Then y'all|Then|Th\xec|Thurh|Toda|Too right|ugeholl|Und|Un|V\xe0|vaj|Vendar|Ve|wann|Wanneer|WEN|Wenn|When y'all|When|Wtedy|Wun|Y'know|Yeah nah|Yna|Youse know like when|Youse know when youse got|Y|Za predpokladu|Za p\u0159edpokladu|Zadani|Zadano|Zadan|Zadate|Zadato|Zak\u0142adaj\u0105c|Zaradi|Zatati|\xdea \xfee|\xdea|\xde\xe1|\xdeegar|\xdeurh|\u0391\u03bb\u03bb\u03ac|\u0394\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5|\u039a\u03b1\u03b9|\u038c\u03c4\u03b1\u03bd|\u03a4\u03cc\u03c4\u03b5|\u0410 \u0442\u0430\u043a\u043e\u0436|\u0410\u0433\u0430\u0440|\u0410\u043b\u0435|\u0410\u043b\u0438|\u0410\u043c\u043c\u043e|\u0410|\u04d8\u0433\u04d9\u0440|\u04d8\u0439\u0442\u0438\u043a|\u04d8\u043c\u043c\u0430|\u0411\u0438\u0440\u043e\u043a|\u0412\u0430|\u0412\u04d9|\u0414\u0430\u0434\u0435\u043d\u043e|\u0414\u0430\u043d\u043e|\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c|\u0415\u0441\u043b\u0438|\u0417\u0430\u0434\u0430\u0442\u0435|\u0417\u0430\u0434\u0430\u0442\u0438|\u0417\u0430\u0434\u0430\u0442\u043e|\u0418|\u0406|\u041a \u0442\u043e\u043c\u0443 \u0436\u0435|\u041a\u0430\u0434\u0430|\u041a\u0430\u0434|\u041a\u043e\u0433\u0430\u0442\u043e|\u041a\u043e\u0433\u0434\u0430|\u041a\u043e\u043b\u0438|\u041b\u04d9\u043a\u0438\u043d|\u041b\u0435\u043a\u0438\u043d|\u041d\u04d9\u0442\u0438\u0497\u04d9\u0434\u04d9|\u041d\u0435\u0445\u0430\u0439|\u041d\u043e|\u041e\u043d\u0434\u0430|\u041f\u0440\u0438\u043f\u0443\u0441\u0442\u0438\u043c\u043e, \u0449\u043e|\u041f\u0440\u0438\u043f\u0443\u0441\u0442\u0438\u043c\u043e|\u041f\u0443\u0441\u0442\u044c|\u0422\u0430\u043a\u0436\u0435|\u0422\u0430|\u0422\u043e\u0433\u0434\u0430|\u0422\u043e\u0434\u0456|\u0422\u043e|\u0423\u043d\u0434\u0430|\u04ba\u04d9\u043c|\u042f\u043a\u0449\u043e|\u05d0\u05d1\u05dc|\u05d0\u05d6\u05d9|\u05d0\u05d6|\u05d1\u05d4\u05d9\u05e0\u05ea\u05df|\u05d5\u05d2\u05dd|\u05db\u05d0\u05e9\u05e8|\u0622\u0646\u06af\u0627\u0647|\u0627\u0630\u0627\u064b|\u0627\u06af\u0631|\u0627\u0645\u0627|\u0627\u0648\u0631|\u0628\u0627 \u0641\u0631\u0636|\u0628\u0627\u0644\u0641\u0631\u0636|\u0628\u0641\u0631\u0636|\u067e\u06be\u0631|\u062a\u0628|\u062b\u0645|\u062c\u0628|\u0639\u0646\u062f\u0645\u0627|\u0641\u0631\u0636 \u06a9\u06cc\u0627|\u0644\u0643\u0646|\u0644\u06cc\u06a9\u0646|\u0645\u062a\u0649|\u0647\u0646\u06af\u0627\u0645\u06cc|\u0648|\u0905\u0917\u0930|\u0914\u0930|\u0915\u0926\u093e|\u0915\u093f\u0928\u094d\u0924\u0941|\u091a\u0942\u0902\u0915\u093f|\u091c\u092c|\u0924\u0925\u093e|\u0924\u0926\u093e|\u0924\u092c|\u092a\u0930\u0928\u094d\u0924\u0941|\u092a\u0930|\u092f\u0926\u093f|\u0a05\u0a24\u0a47|\u0a1c\u0a26\u0a4b\u0a02|\u0a1c\u0a3f\u0a35\u0a47\u0a02 \u0a15\u0a3f|\u0a1c\u0a47\u0a15\u0a30|\u0a24\u0a26|\u0a2a\u0a30|\u0c05\u0c2a\u0c4d\u0c2a\u0c41\u0c21\u0c41|\u0c08 \u0c2a\u0c30\u0c3f\u0c38\u0c4d\u0c25\u0c3f\u0c24\u0c3f\u0c32\u0c4b|\u0c15\u0c3e\u0c28\u0c3f|\u0c1a\u0c46\u0c2a\u0c4d\u0c2a\u0c2c\u0c21\u0c3f\u0c28\u0c26\u0c3f|\u0c2e\u0c30\u0c3f\u0c2f\u0c41|\u0c86\u0ca6\u0cb0\u0cc6|\u0ca8\u0c82\u0ca4\u0cb0|\u0ca8\u0cbf\u0cd5\u0ca1\u0cbf\u0ca6|\u0cae\u0ca4\u0ccd\u0ca4\u0cc1|\u0cb8\u0ccd\u0ca5\u0cbf\u0ca4\u0cbf\u0caf\u0ca8\u0ccd\u0ca8\u0cc1|\u0e01\u0e33\u0e2b\u0e19\u0e14\u0e43\u0e2b\u0e49|\u0e14\u0e31\u0e07\u0e19\u0e31\u0e49\u0e19|\u0e41\u0e15\u0e48|\u0e40\u0e21\u0e37\u0e48\u0e2d|\u0e41\u0e25\u0e30|\uadf8\ub7ec\uba74<|\uadf8\ub9ac\uace0<|\ub2e8<|\ub9cc\uc57d<|\ub9cc\uc77c<|\uba3c\uc800<|\uc870\uac74<|\ud558\uc9c0\ub9cc<|\u304b\u3064<|\u3057\u304b\u3057<|\u305f\u3060\u3057<|\u306a\u3089\u3070<|\u3082\u3057<|\u4e26\u4e14<|\u4f46\u3057<|\u4f46\u662f<|\u5047\u5982<|\u5047\u5b9a<|\u5047\u8a2d<|\u5047\u8bbe<|\u524d\u63d0<|\u540c\u65f6<|\u540c\u6642<|\u5e76\u4e14<|\u5f53<|\u7576<|\u800c\u4e14<|\u90a3\u4e48<|\u90a3\u9ebc<)(?=[ \t]+)/,lookbehind:!0},string:{pattern:/("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')/,inside:{outline:{pattern:/<[^>]+?>/,alias:"variable"}}},outline:{pattern:/<[^>]+?>/,alias:"variable"}},Prism.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(\\?.)*?\1/m,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s(--|-)\w+/m}},coord:/^@@.*@@$/m,commit_sha1:/^commit \w{40}$/m},Prism.languages.glsl=Prism.languages.extend("clike",{comment:[/\/\*[\w\W]*?\*\//,/\/\/(?:\\(?:\r\n|[\s\S])|.)*/],number:/\b(?:0x[\da-f]+|(?:\.\d+|\d+\.?\d*)(?:e[+-]?\d+)?)[ulf]*\b/i,keyword:/\b(?:attribute|const|uniform|varying|buffer|shared|coherent|volatile|restrict|readonly|writeonly|atomic_uint|layout|centroid|flat|smooth|noperspective|patch|sample|break|continue|do|for|while|switch|case|default|if|else|subroutine|in|out|inout|float|double|int|void|bool|true|false|invariant|precise|discard|return|d?mat[234](?:x[234])?|[ibdu]?vec[234]|uint|lowp|mediump|highp|precision|[iu]?sampler[123]D|[iu]?samplerCube|sampler[12]DShadow|samplerCubeShadow|[iu]?sampler[12]DArray|sampler[12]DArrayShadow|[iu]?sampler2DRect|sampler2DRectShadow|[iu]?samplerBuffer|[iu]?sampler2DMS(?:Array)?|[iu]?samplerCubeArray|samplerCubeArrayShadow|[iu]?image[123]D|[iu]?image2DRect|[iu]?imageCube|[iu]?imageBuffer|[iu]?image[12]DArray|[iu]?imageCubeArray|[iu]?image2DMS(?:Array)?|struct|common|partition|active|asm|class|union|enum|typedef|template|this|resource|goto|inline|noinline|public|static|extern|external|interface|long|short|half|fixed|unsigned|superp|input|output|hvec[234]|fvec[234]|sampler3DRect|filter|sizeof|cast|namespace|using)\b/}),Prism.languages.insertBefore("glsl","comment",{preprocessor:{pattern:/(^[ \t]*)#(?:(?:define|undef|if|ifdef|ifndef|else|elif|endif|error|pragma|extension|version|line)\b)?/m,lookbehind:!0,alias:"builtin"}}),Prism.languages.go=Prism.languages.extend("clike",{keyword:/\b(break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,builtin:/\b(bool|byte|complex(64|128)|error|float(32|64)|rune|string|u?int(8|16|32|64|)|uintptr|append|cap|close|complex|copy|delete|imag|len|make|new|panic|print(ln)?|real|recover)\b/,"boolean":/\b(_|iota|nil|true|false)\b/,operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,number:/\b(-?(0x[a-f\d]+|(\d+\.?\d*|\.\d+)(e[-+]?\d+)?)i?)\b/i,string:/("|'|`)(\\?.|\r|\n)*?\1/}),delete Prism.languages.go["class-name"],Prism.languages.graphql={comment:/#.*/,string:{pattern:/"(?:\\.|[^\\"])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/,"boolean":/\b(?:true|false)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":/[a-z_]\w*(?=\s*:)/i,keyword:[{pattern:/(fragment\s+(?!on)[a-z_]\w*\s+|\.\.\.\s*)on\b/,lookbehind:!0},/\b(?:query|fragment|mutation)\b/],operator:/!|=|\.{3}/,punctuation:/[!(){}\[\]:=,]/},Prism.languages.groovy=Prism.languages.extend("clike",{keyword:/\b(as|def|in|abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/,string:[{pattern:/("""|''')[\W\w]*?\1|(\$\/)(\$\/\$|[\W\w])*?\/\$/,greedy:!0},{pattern:/("|'|\/)(?:\\?.)*?\1/,greedy:!0}],number:/\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?[\d]+)?)[glidf]?\b/i,operator:{pattern:/(^|[^.])(~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.{1,2}(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,lookbehind:!0},punctuation:/\.+|[{}[\];(),:$]/}),Prism.languages.insertBefore("groovy","string",{shebang:{pattern:/#!.+/,alias:"comment"}}),Prism.languages.insertBefore("groovy","punctuation",{"spock-block":/\b(setup|given|when|then|and|cleanup|expect|where):/}),Prism.languages.insertBefore("groovy","function",{annotation:{alias:"punctuation",pattern:/(^|[^.])@\w+/,lookbehind:!0}}),Prism.hooks.add("wrap",function(e){if("groovy"===e.language&&"string"===e.type){var t=e.content[0];if("'"!=t){var n=/([^\\])(\$(\{.*?\}|[\w\.]+))/;"$"===t&&(n=/([^\$])(\$(\{.*?\}|[\w\.]+))/),e.content=e.content.replace(/&/g,"&").replace(/</g,"<"),e.content=Prism.highlight(e.content,{expression:{pattern:n,lookbehind:!0,inside:Prism.languages.groovy}}),e.classes.push("/"===t?"regex":"gstring")}}}),function(e){e.languages.haml={"multiline-comment":{pattern:/((?:^|\r?\n|\r)([\t ]*))(?:\/|-#).*((?:\r?\n|\r)\2[\t ]+.+)*/,lookbehind:!0,alias:"comment"},"multiline-code":[{pattern:/((?:^|\r?\n|\r)([\t ]*)(?:[~-]|[&!]?=)).*,[\t ]*((?:\r?\n|\r)\2[\t ]+.*,[\t ]*)*((?:\r?\n|\r)\2[\t ]+.+)/,lookbehind:!0,inside:{rest:e.languages.ruby}},{pattern:/((?:^|\r?\n|\r)([\t ]*)(?:[~-]|[&!]?=)).*\|[\t ]*((?:\r?\n|\r)\2[\t ]+.*\|[\t ]*)*/,lookbehind:!0,inside:{rest:e.languages.ruby}}],filter:{pattern:/((?:^|\r?\n|\r)([\t ]*)):[\w-]+((?:\r?\n|\r)(?:\2[\t ]+.+|\s*?(?=\r?\n|\r)))+/,lookbehind:!0,inside:{"filter-name":{pattern:/^:[\w-]+/,alias:"variable"}}},markup:{pattern:/((?:^|\r?\n|\r)[\t ]*)<.+/,lookbehind:!0,inside:{rest:e.languages.markup}},doctype:{pattern:/((?:^|\r?\n|\r)[\t ]*)!!!(?: .+)?/,lookbehind:!0},tag:{pattern:/((?:^|\r?\n|\r)[\t ]*)[%.#][\w\-#.]*[\w\-](?:\([^)]+\)|\{(?:\{[^}]+\}|[^}])+\}|\[[^\]]+\])*[\/<>]*/,lookbehind:!0,inside:{attributes:[{pattern:/(^|[^#])\{(?:\{[^}]+\}|[^}])+\}/,lookbehind:!0,inside:{rest:e.languages.ruby}},{pattern:/\([^)]+\)/,inside:{"attr-value":{pattern:/(=\s*)(?:"(?:\\?.)*?"|[^)\s]+)/,lookbehind:!0},"attr-name":/[\w:-]+(?=\s*!?=|\s*[,)])/,punctuation:/[=(),]/}},{pattern:/\[[^\]]+\]/,inside:{rest:e.languages.ruby}}],punctuation:/[<>]/}},code:{pattern:/((?:^|\r?\n|\r)[\t ]*(?:[~-]|[&!]?=)).+/,lookbehind:!0,inside:{rest:e.languages.ruby}},interpolation:{pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"},rest:e.languages.ruby}},punctuation:{pattern:/((?:^|\r?\n|\r)[\t ]*)[~=\-&!]+/,lookbehind:!0}};for(var t="((?:^|\\r?\\n|\\r)([\\t ]*)):{{filter_name}}((?:\\r?\\n|\\r)(?:\\2[\\t ]+.+|\\s*?(?=\\r?\\n|\\r)))+",n=["css",{filter:"coffee",language:"coffeescript"},"erb","javascript","less","markdown","ruby","scss","textile"],a={},i=0,r=n.length;i@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~\s]+/}}}),a.languages.insertBefore("handlebars","tag",{"handlebars-comment":{pattern:/\{\{![\w\W]*?\}\}/,alias:["handlebars","comment"]}}),a.hooks.add("before-highlight",function(t){"handlebars"===t.language&&(t.tokenStack=[],t.code=t.code.replace(e,function(e){return t.tokenStack.push(e),"___HANDLEBARS"+t.tokenStack.length+"___"}))}),a.hooks.add("after-highlight",function(e){if("handlebars"===e.language){for(var t,n=0;t=e.tokenStack[n];n++)e.highlightedCode=e.highlightedCode.replace("___HANDLEBARS"+(n+1)+"___",a.highlight(t,e.grammar,"handlebars").replace(/\$/g,"$$$$"));e.element.innerHTML=e.highlightedCode}})}(Prism),Prism.languages.haskell={comment:{pattern:/(^|[^-!#$%*+=?&@|~.:<>^\\\/])(--[^-!#$%*+=?&@|~.:<>^\\\/].*|{-[\w\W]*?-})/m,lookbehind:!0},"char":/'([^\\']|\\([abfnrtv\\"'&]|\^[A-Z@[\]\^_]|NUL|SOH|STX|ETX|EOT|ENQ|ACK|BEL|BS|HT|LF|VT|FF|CR|SO|SI|DLE|DC1|DC2|DC3|DC4|NAK|SYN|ETB|CAN|EM|SUB|ESC|FS|GS|RS|US|SP|DEL|\d+|o[0-7]+|x[0-9a-fA-F]+))'/,string:{pattern:/"([^\\"]|\\([abfnrtv\\"'&]|\^[A-Z@[\]\^_]|NUL|SOH|STX|ETX|EOT|ENQ|ACK|BEL|BS|HT|LF|VT|FF|CR|SO|SI|DLE|DC1|DC2|DC3|DC4|NAK|SYN|ETB|CAN|EM|SUB|ESC|FS|GS|RS|US|SP|DEL|\d+|o[0-7]+|x[0-9a-fA-F]+)|\\\s+\\)*"/,greedy:!0},keyword:/\b(case|class|data|deriving|do|else|if|in|infixl|infixr|instance|let|module|newtype|of|primitive|then|type|where)\b/,import_statement:{pattern:/(\r?\n|\r|^)\s*import\s+(qualified\s+)?([A-Z][_a-zA-Z0-9']*)(\.[A-Z][_a-zA-Z0-9']*)*(\s+as\s+([A-Z][_a-zA-Z0-9']*)(\.[A-Z][_a-zA-Z0-9']*)*)?(\s+hiding\b)?/m,inside:{keyword:/\b(import|qualified|as|hiding)\b/}}, +builtin:/\b(abs|acos|acosh|all|and|any|appendFile|approxRational|asTypeOf|asin|asinh|atan|atan2|atanh|basicIORun|break|catch|ceiling|chr|compare|concat|concatMap|const|cos|cosh|curry|cycle|decodeFloat|denominator|digitToInt|div|divMod|drop|dropWhile|either|elem|encodeFloat|enumFrom|enumFromThen|enumFromThenTo|enumFromTo|error|even|exp|exponent|fail|filter|flip|floatDigits|floatRadix|floatRange|floor|fmap|foldl|foldl1|foldr|foldr1|fromDouble|fromEnum|fromInt|fromInteger|fromIntegral|fromRational|fst|gcd|getChar|getContents|getLine|group|head|id|inRange|index|init|intToDigit|interact|ioError|isAlpha|isAlphaNum|isAscii|isControl|isDenormalized|isDigit|isHexDigit|isIEEE|isInfinite|isLower|isNaN|isNegativeZero|isOctDigit|isPrint|isSpace|isUpper|iterate|last|lcm|length|lex|lexDigits|lexLitChar|lines|log|logBase|lookup|map|mapM|mapM_|max|maxBound|maximum|maybe|min|minBound|minimum|mod|negate|not|notElem|null|numerator|odd|or|ord|otherwise|pack|pi|pred|primExitWith|print|product|properFraction|putChar|putStr|putStrLn|quot|quotRem|range|rangeSize|read|readDec|readFile|readFloat|readHex|readIO|readInt|readList|readLitChar|readLn|readOct|readParen|readSigned|reads|readsPrec|realToFrac|recip|rem|repeat|replicate|return|reverse|round|scaleFloat|scanl|scanl1|scanr|scanr1|seq|sequence|sequence_|show|showChar|showInt|showList|showLitChar|showParen|showSigned|showString|shows|showsPrec|significand|signum|sin|sinh|snd|sort|span|splitAt|sqrt|subtract|succ|sum|tail|take|takeWhile|tan|tanh|threadToIOResult|toEnum|toInt|toInteger|toLower|toRational|toUpper|truncate|uncurry|undefined|unlines|until|unwords|unzip|unzip3|userError|words|writeFile|zip|zip3|zipWith|zipWith3)\b/,number:/\b(\d+(\.\d+)?(e[+-]?\d+)?|0o[0-7]+|0x[0-9a-f]+)\b/i,operator:/\s\.\s|[-!#$%*+=?&@|~.:<>^\\\/]*\.[-!#$%*+=?&@|~.:<>^\\\/]+|[-!#$%*+=?&@|~.:<>^\\\/]+\.[-!#$%*+=?&@|~.:<>^\\\/]*|[-!#$%*+=?&@|~:<>^\\\/]+|`([A-Z][_a-zA-Z0-9']*\.)*[_a-z][_a-zA-Z0-9']*`/,hvariable:/\b([A-Z][_a-zA-Z0-9']*\.)*[_a-z][_a-zA-Z0-9']*\b/,constant:/\b([A-Z][_a-zA-Z0-9']*\.)*[A-Z][_a-zA-Z0-9']*\b/,punctuation:/[{}[\];(),.:]/},Prism.languages.haxe=Prism.languages.extend("clike",{string:{pattern:/(["'])(?:(?!\1)[^\\]|\\[\s\S])*\1/,inside:{interpolation:{pattern:/(^|[^\\])\$(?:\w+|\{[^}]+\})/,lookbehind:!0,inside:{interpolation:{pattern:/^\$\w*/,alias:"variable"}}}}},keyword:/\bthis\b|\b(?:abstract|as|break|case|cast|catch|class|continue|default|do|dynamic|else|enum|extends|extern|from|for|function|if|implements|import|in|inline|interface|macro|new|null|override|public|private|return|static|super|switch|throw|to|try|typedef|using|var|while)(?!\.)\b/,operator:/\.{3}|\+\+?|-[->]?|[=!]=?|&&?|\|\|?|<[<=]?|>[>=]?|[*\/%~^]/}),Prism.languages.insertBefore("haxe","class-name",{regex:{pattern:/~\/(?:[^\/\\\r\n]|\\.)+\/[igmsu]*/}}),Prism.languages.insertBefore("haxe","keyword",{preprocessor:{pattern:/#\w+/,alias:"builtin"},metadata:{pattern:/@:?\w+/,alias:"symbol"},reification:{pattern:/\$(?:\w+|(?=\{))/,alias:"variable"}}),Prism.languages.haxe.string.inside.interpolation.inside.rest=Prism.util.clone(Prism.languages.haxe),delete Prism.languages.haxe["class-name"],Prism.languages.http={"request-line":{pattern:/^(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b\shttps?:\/\/\S+\sHTTP\/[0-9.]+/m,inside:{property:/^(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b/,"attr-name":/:\w+/}},"response-status":{pattern:/^HTTP\/1.[01] [0-9]+.*/m,inside:{property:{pattern:/(^HTTP\/1.[01] )[0-9]+.*/i,lookbehind:!0}}},"header-name":{pattern:/^[\w-]+:(?=.)/m,alias:"keyword"}};var httpLanguages={"application/json":Prism.languages.javascript,"application/xml":Prism.languages.markup,"text/xml":Prism.languages.markup,"text/html":Prism.languages.markup};for(var contentType in httpLanguages)if(httpLanguages[contentType]){var options={};options[contentType]={pattern:new RegExp("(content-type:\\s*"+contentType+"[\\w\\W]*?)(?:\\r?\\n|\\r){2}[\\w\\W]*","i"),lookbehind:!0,inside:{rest:httpLanguages[contentType]}},Prism.languages.insertBefore("http","header-name",options)}Prism.languages.icon={comment:/#.*/,string:/(["'])(?:(?!\1)[^\\\r\n]|\\.|_(?:\r?\n|\r))*\1/,number:/\b(?:\d+r[a-z\d]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)\b|\.\d+\b/i,"builtin-keyword":{pattern:/&(?:allocated|ascii|clock|collections|cset|current|date|dateline|digits|dump|e|error(?:number|text|value)?|errout|fail|features|file|host|input|lcase|letters|level|line|main|null|output|phi|pi|pos|progname|random|regions|source|storage|subject|time|trace|ucase|version)\b/,alias:"variable"},directive:{pattern:/\$\w+/,alias:"builtin"},keyword:/\b(?:break|by|case|create|default|do|else|end|every|fail|global|if|initial|invocable|link|local|next|not|of|procedure|record|repeat|return|static|suspend|then|to|until|while)\b/,"function":/(?!\d)\w+(?=\s*[({]|\s*!\s*\[)/,operator:/[+-]:(?!=)|(?:[\/?@^%&]|\+\+?|--?|==?=?|~==?=?|\*\*?|\|\|\|?|<(?:->?|>?=?)(?::=)?|:(?:=:?)?|[!.\\|~]/,punctuation:/[\[\](){},;]/},Prism.languages.inform7={string:{pattern:/"[^"]*"/,inside:{substitution:{pattern:/\[[^\]]+\]/,inside:{delimiter:{pattern:/\[|\]/,alias:"punctuation"}}}}},comment:/\[[^\]]+\]/,title:{pattern:/^[ \t]*(?:volume|book|part(?! of)|chapter|section|table)\b.+/im,alias:"important"},number:{pattern:/(^|[^-])(?:(?:\b|-)\d+(?:\.\d+)?(?:\^\d+)?\w*|\b(?:one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve))\b(?!-)/i,lookbehind:!0},verb:{pattern:/(^|[^-])\b(?:applying to|are|attacking|answering|asking|be(?:ing)?|burning|buying|called|carries|carry(?! out)|carrying|climbing|closing|conceal(?:s|ing)?|consulting|contain(?:s|ing)?|cutting|drinking|dropping|eating|enclos(?:es?|ing)|entering|examining|exiting|getting|giving|going|ha(?:ve|s|ving)|hold(?:s|ing)?|impl(?:y|ies)|incorporat(?:es?|ing)|inserting|is|jumping|kissing|listening|locking|looking|mean(?:s|ing)?|opening|provid(?:es?|ing)|pulling|pushing|putting|relat(?:es?|ing)|removing|searching|see(?:s|ing)?|setting|showing|singing|sleeping|smelling|squeezing|switching|support(?:s|ing)?|swearing|taking|tasting|telling|thinking|throwing|touching|turning|tying|unlock(?:s|ing)?|var(?:y|ies|ying)|waiting|waking|waving|wear(?:s|ing)?)\b(?!-)/i,lookbehind:!0,alias:"operator"},keyword:{pattern:/(^|[^-])\b(?:after|before|carry out|check|continue the action|definition(?= *:)|do nothing|else|end (?:if|unless|the story)|every turn|if|include|instead(?: of)?|let|move|no|now|otherwise|repeat|report|resume the story|rule for|running through|say(?:ing)?|stop the action|test|try(?:ing)?|understand|unless|use|when|while|yes)\b(?!-)/i,lookbehind:!0},property:{pattern:/(^|[^-])\b(?:adjacent(?! to)|carried|closed|concealed|contained|dark|described|edible|empty|enclosed|enterable|even|female|fixed in place|full|handled|held|improper-named|incorporated|inedible|invisible|lighted|lit|lock(?:able|ed)|male|marked for listing|mentioned|negative|neuter|non-(?:empty|full|recurring)|odd|opaque|open(?:able)?|plural-named|portable|positive|privately-named|proper-named|provided|publically-named|pushable between rooms|recurring|related|rubbing|scenery|seen|singular-named|supported|swinging|switch(?:able|ed(?: on| off)?)|touch(?:able|ed)|transparent|unconcealed|undescribed|unlit|unlocked|unmarked for listing|unmentioned|unopenable|untouchable|unvisited|variable|visible|visited|wearable|worn)\b(?!-)/i,lookbehind:!0,alias:"symbol"},position:{pattern:/(^|[^-])\b(?:above|adjacent to|back side of|below|between|down|east|everywhere|front side|here|in|inside(?: from)?|north(?:east|west)?|nowhere|on(?: top of)?|other side|outside(?: from)?|parts? of|regionally in|south(?:east|west)?|through|up|west|within)\b(?!-)/i,lookbehind:!0,alias:"keyword"},type:{pattern:/(^|[^-])\b(?:actions?|activit(?:y|ies)|actors?|animals?|backdrops?|containers?|devices?|directions?|doors?|holders?|kinds?|lists?|m[ae]n|nobody|nothing|nouns?|numbers?|objects?|people|persons?|player(?:'s holdall)?|regions?|relations?|rooms?|rule(?:book)?s?|scenes?|someone|something|supporters?|tables?|texts?|things?|time|vehicles?|wom[ae]n)\b(?!-)/i,lookbehind:!0,alias:"variable"},punctuation:/[.,:;(){}]/},Prism.languages.inform7.string.inside.substitution.inside.rest=Prism.util.clone(Prism.languages.inform7),Prism.languages.inform7.string.inside.substitution.inside.rest.text={pattern:/\S(?:\s*\S)*/,alias:"comment"},Prism.languages.ini={comment:/^[ \t]*;.*$/m,important:/\[.*?\]/,constant:/^[ \t]*[^\s=]+?(?=[ \t]*=)/m,"attr-value":{pattern:/=.*/,inside:{punctuation:/^[=]/}}},Prism.languages.j={comment:/\bNB\..*/,string:/'(?:''|[^'\r\n])*'/,keyword:/\b(?:(?:adverb|conjunction|CR|def|define|dyad|LF|monad|noun|verb)\b|(?:assert|break|case|catch[dt]?|continue|do|else|elseif|end|fcase|for|for_\w+|goto_\w+|if|label_\w+|return|select|throw|try|while|whilst)\.)/,verb:{pattern:/(?!\^:|;\.|[=!][.:])(?:\{(?:\.|::?)?|p(?:\.\.?|:)|[=!\]]|[<>+*\-%$|,#][.:]?|[\^?]\.?|[;\[]:?|[~}"i][.:]|[ACeEIjLor]\.|(?:[_\/\\qsux]|_?\d):)/,alias:"keyword"},number:/\b_?(?:(?!\d:)\d+(?:\.\d+)?(?:(?:[ejpx]|ad|ar)_?\d+(?:\.\d+)?)*(?:b_?[\da-z]+(?:\.[\da-z]+)?)?|_(?!\.))/,adverb:{pattern:/[~}]|[\/\\]\.?|[bfM]\.|t[.:]/,alias:"builtin"},operator:/[=a][.:]|_\./,conjunction:{pattern:/&(?:\.:?|:)?|[.:@][.:]?|[!D][.:]|[;dHT]\.|`:?|[\^LS]:|"/,alias:"variable"},punctuation:/[()]/},function(e){e.languages.jade={comment:{pattern:/(^([\t ]*))\/\/.*((?:\r?\n|\r)\2[\t ]+.+)*/m,lookbehind:!0},"multiline-script":{pattern:/(^([\t ]*)script\b.*\.[\t ]*)((?:\r?\n|\r(?!\n))(?:\2[\t ]+.+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0,inside:{rest:e.languages.javascript}},filter:{pattern:/(^([\t ]*)):.+((?:\r?\n|\r(?!\n))(?:\2[\t ]+.+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0,inside:{"filter-name":{pattern:/^:[\w-]+/,alias:"variable"}}},"multiline-plain-text":{pattern:/(^([\t ]*)[\w\-#.]+\.[\t ]*)((?:\r?\n|\r(?!\n))(?:\2[\t ]+.+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0},markup:{pattern:/(^[\t ]*)<.+/m,lookbehind:!0,inside:{rest:e.languages.markup}},doctype:{pattern:/((?:^|\n)[\t ]*)doctype(?: .+)?/,lookbehind:!0},"flow-control":{pattern:/(^[\t ]*)(?:if|unless|else|case|when|default|each|while)\b(?: .+)?/m,lookbehind:!0,inside:{each:{pattern:/^each .+? in\b/,inside:{keyword:/\b(?:each|in)\b/,punctuation:/,/}},branch:{pattern:/^(?:if|unless|else|case|when|default|while)\b/,alias:"keyword"},rest:e.languages.javascript}},keyword:{pattern:/(^[\t ]*)(?:block|extends|include|append|prepend)\b.+/m,lookbehind:!0},mixin:[{pattern:/(^[\t ]*)mixin .+/m,lookbehind:!0,inside:{keyword:/^mixin/,"function":/\w+(?=\s*\(|\s*$)/,punctuation:/[(),.]/}},{pattern:/(^[\t ]*)\+.+/m,lookbehind:!0,inside:{name:{pattern:/^\+\w+/,alias:"function"},rest:e.languages.javascript}}],script:{pattern:/(^[\t ]*script(?:(?:&[^(]+)?\([^)]+\))*[\t ]+).+/m,lookbehind:!0,inside:{rest:e.languages.javascript}},"plain-text":{pattern:/(^[\t ]*(?!-)[\w\-#.]*[\w\-](?:(?:&[^(]+)?\([^)]+\))*\/?[\t ]+).+/m,lookbehind:!0},tag:{pattern:/(^[\t ]*)(?!-)[\w\-#.]*[\w\-](?:(?:&[^(]+)?\([^)]+\))*\/?:?/m,lookbehind:!0,inside:{attributes:[{pattern:/&[^(]+\([^)]+\)/,inside:{rest:e.languages.javascript}},{pattern:/\([^)]+\)/,inside:{"attr-value":{pattern:/(=\s*)(?:\{[^}]*\}|[^,)\r\n]+)/,lookbehind:!0,inside:{rest:e.languages.javascript}},"attr-name":/[\w-]+(?=\s*!?=|\s*[,)])/,punctuation:/[!=(),]+/}}],punctuation:/:/}},code:[{pattern:/(^[\t ]*(?:-|!?=)).+/m,lookbehind:!0,inside:{rest:e.languages.javascript}}],punctuation:/[.\-!=|]+/};for(var t="(^([\\t ]*)):{{filter_name}}((?:\\r?\\n|\\r(?!\\n))(?:\\2[\\t ]+.+|\\s*?(?=\\r?\\n|\\r)))+",n=[{filter:"atpl",language:"twig"},{filter:"coffee",language:"coffeescript"},"ejs","handlebars","hogan","less","livescript","markdown","mustache","plates",{filter:"sass",language:"scss"},"stylus","swig"],a={},i=0,r=n.length;i>?>?=?|==?|&[&=]?|\|[|=]?|\*=?|\/=?|%=?|\^=?|[?:~])/m,lookbehind:!0}}),Prism.languages.insertBefore("java","function",{annotation:{alias:"punctuation",pattern:/(^|[^.])@\w+/,lookbehind:!0}}),Prism.languages.json={property:/".*?"(?=\s*:)/gi,string:/"(?!:)(\\?[^"])*?"(?!:)/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,punctuation:/[{}[\]);,]/g,operator:/:/g,"boolean":/\b(true|false)\b/gi,"null":/\bnull\b/gi},Prism.languages.jsonp=Prism.languages.json,Prism.languages.julia={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},string:/"""[\s\S]+?"""|'''[\s\S]+?'''|("|')(\\?.)*?\1/,keyword:/\b(abstract|baremodule|begin|bitstype|break|catch|ccall|const|continue|do|else|elseif|end|export|finally|for|function|global|if|immutable|import|importall|let|local|macro|module|print|println|quote|return|try|type|typealias|using|while)\b/,"boolean":/\b(true|false)\b/,number:/\b-?(0[box])?(?:[\da-f]+\.?\d*|\.\d+)(?:[efp][+-]?\d+)?j?\b/i,operator:/\+=?|-=?|\*=?|\/[\/=]?|\\=?|\^=?|%=?|\xf7=?|!=?=?|&=?|\|[=>]?|\$=?|<(?:<=?|[=:])?|>(?:=|>>?=?)?|==?=?|[~\u2260\u2264\u2265]/,punctuation:/[{}[\];(),.:]/},Prism.languages.keyman={comment:/\bc\s.*/i,"function":/\[\s*((CTRL|SHIFT|ALT|LCTRL|RCTRL|LALT|RALT|CAPS|NCAPS)\s+)*([TKU]_[a-z0-9_?]+|".+?"|'.+?')\s*\]/i,string:/("|')((?!\1).)*\1/,bold:[/&(baselayout|bitmap|capsononly|capsalwaysoff|shiftfreescaps|copyright|ethnologuecode|hotkey|includecodes|keyboardversion|kmw_embedcss|kmw_embedjs|kmw_helpfile|kmw_helptext|kmw_rtl|language|layer|layoutfile|message|mnemoniclayout|name|oldcharposmatching|platform|targets|version|visualkeyboard|windowslanguages)\b/i,/\b(bitmap|bitmaps|caps on only|caps always off|shift frees caps|copyright|hotkey|language|layout|message|name|version)\b/i],keyword:/\b(any|baselayout|beep|call|context|deadkey|dk|if|index|layer|notany|nul|outs|platform|return|reset|save|set|store|use)\b/i,atrule:/\b(ansi|begin|unicode|group|using keys|match|nomatch)\b/i,number:/\b(U\+[\dA-F]+|d\d+|x[\da-f]+|\d+)\b/i,operator:/[+>\\,()]/,tag:/\$(keyman|kmfl|weaver|keymanweb|keymanonly):/i},function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|else|enum|final|finally|for|fun|get|if|import|in|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|out|override|package|private|protected|public|reified|return|sealed|set|super|tailrec|this|throw|to|try|val|var|when|where|while)\b/,lookbehind:!0},"function":[/\w+(?=\s*\()/,{pattern:/(\.)\w+(?=\s*\{)/,lookbehind:!0}],number:/\b(?:0[bx][\da-fA-F]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"],e.languages.insertBefore("kotlin","string",{"raw-string":{pattern:/(["'])\1\1[\s\S]*?\1{3}/,alias:"string"}}),e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\w+@|@\w+/,alias:"symbol"}});var t=[{pattern:/\$\{[^}]+\}/,inside:{delimiter:{pattern:/^\$\{|\}$/,alias:"variable"},rest:e.util.clone(e.languages.kotlin)}},{pattern:/\$\w+/,alias:"variable"}];e.languages.kotlin.string.inside=e.languages.kotlin["raw-string"].inside={interpolation:t}}(Prism),function(){var e=/\\([^a-z()[\]]|[a-z\*]+)/i,t={"equation-command":{pattern:e,alias:"regex"}};Prism.languages.latex={comment:/%.*/m,cdata:{pattern:/(\\begin\{((?:verbatim|lstlisting)\*?)\})([\w\W]*?)(?=\\end\{\2\})/,lookbehind:!0},equation:[{pattern:/\$(?:\\?[\w\W])*?\$|\\\((?:\\?[\w\W])*?\\\)|\\\[(?:\\?[\w\W])*?\\\]/,inside:t,alias:"string"},{pattern:/(\\begin\{((?:equation|math|eqnarray|align|multline|gather)\*?)\})([\w\W]*?)(?=\\end\{\2\})/,lookbehind:!0,inside:t,alias:"string"}],keyword:{pattern:/(\\(?:begin|end|ref|cite|label|usepackage|documentclass)(?:\[[^\]]+\])?\{)[^}]+(?=\})/,lookbehind:!0},url:{pattern:/(\\url\{)[^}]+(?=\})/,lookbehind:!0},headline:{pattern:/(\\(?:part|chapter|section|subsection|frametitle|subsubsection|paragraph|subparagraph|subsubparagraph|subsubsubparagraph)\*?(?:\[[^\]]+\])?\{)[^}]+(?=\}(?:\[[^\]]+\])?)/,lookbehind:!0,alias:"class-name"},"function":{pattern:e,alias:"selector"},punctuation:/[[\]{}&]/}}(),Prism.languages.less=Prism.languages.extend("css",{comment:[/\/\*[\w\W]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-]+?(?:\([^{}]+\)|[^(){};])*?(?=\s*\{)/i,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\([^{}]*\)|[^{};@])*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/i,punctuation:/[{}();:,]/,operator:/[+\-*\/]/}),Prism.languages.insertBefore("less","punctuation",{"function":Prism.languages.less["function"]}),Prism.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-]+.*?(?=[(;])/,lookbehind:!0,alias:"function"}}),Prism.languages.livescript={"interpolated-string":{pattern:/("""|")(?:\\[\s\S]|(?!\1)[^\\])*\1/,greedy:!0,inside:{variable:{pattern:/(^|[^\\])#[a-z_](?:-?[a-z]|\d)*/m,lookbehind:!0},interpolation:{pattern:/(^|[^\\])#\{[^}]+\}/m,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^#\{|\}$/,alias:"variable"}}},string:/[\s\S]+/}},comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0}],string:[{pattern:/('''|')(?:\\[\s\S]|(?!\1)[^\\])*\1/,greedy:!0},{pattern:/<\[[\s\S]*?\]>/,greedy:!0},/\\[^\s,;\])}]+/],regex:[{pattern:/\/\/(\[.+?]|\\.|(?!\/\/)[^\\])+\/\/[gimyu]{0,5}/,greedy:!0,inside:{comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0}}},{pattern:/\/(\[.+?]|\\.|[^\/\\\r\n])+\/[gimyu]{0,5}/,greedy:!0}],keyword:{pattern:/(^|(?!-).)\b(?:break|case|catch|class|const|continue|default|do|else|extends|fallthrough|finally|for(?: ever)?|function|if|implements|it|let|loop|new|null|otherwise|own|return|super|switch|that|then|this|throw|try|unless|until|var|void|when|while|yield)(?!-)\b/m,lookbehind:!0},"keyword-operator":{pattern:/(^|[^-])\b(?:(?:delete|require|typeof)!|(?:and|by|delete|export|from|import(?: all)?|in|instanceof|is(?:nt| not)?|not|of|or|til|to|typeof|with|xor)(?!-)\b)/m,lookbehind:!0,alias:"operator"},"boolean":{pattern:/(^|[^-])\b(?:false|no|off|on|true|yes)(?!-)\b/m,lookbehind:!0},argument:{pattern:/(^|(?!\.&\.)[^&])&(?!&)\d*/m,lookbehind:!0,alias:"variable"},number:/\b(?:\d+~[\da-z]+|\d[\d_]*(?:\.\d[\d_]*)?(?:[a-z]\w*)?)/i,identifier:/[a-z_](?:-?[a-z]|\d)*/i,operator:[{pattern:/( )\.(?= )/,lookbehind:!0},/\.(?:[=~]|\.\.?)|\.(?:[&|^]|<<|>>>?)\.|:(?:=|:=?)|&&|\|[|>]|<(?:<[>=?]?|-(?:->?|>)?|\+\+?|@@?|%%?|\*\*?|!(?:~?=|--?>|~?~>)?|~(?:~?>|=)?|==?|\^\^?|[\/?]/],punctuation:/[(){}\[\]|.,:;`]/},Prism.languages.livescript["interpolated-string"].inside.interpolation.inside.rest=Prism.languages.livescript,Prism.languages.lolcode={comment:[/\bOBTW\s+[\s\S]*?\s+TLDR\b/,/\bBTW.+/],string:{pattern:/"(?::.|[^"])*"/,inside:{variable:/:\{[^}]+\}/,symbol:[/:\([a-f\d]+\)/i,/:\[[^\]]+\]/,/:[)>o":]/]}},number:/(-|\b)\d*\.?\d+/,symbol:{pattern:/(^|\s)(?:A )?(?:YARN|NUMBR|NUMBAR|TROOF|BUKKIT|NOOB)(?=\s|,|$)/,lookbehind:!0,inside:{keyword:/A(?=\s)/}},label:{pattern:/((?:^|\s)(?:IM IN YR|IM OUTTA YR) )[a-zA-Z]\w*/,lookbehind:!0,alias:"string"},"function":{pattern:/((?:^|\s)(?:I IZ|HOW IZ I|IZ) )[a-zA-Z]\w*/,lookbehind:!0},keyword:[{pattern:/(^|\s)(?:O HAI IM|KTHX|HAI|KTHXBYE|I HAS A|ITZ(?: A)?|R|AN|MKAY|SMOOSH|MAEK|IS NOW(?: A)?|VISIBLE|GIMMEH|O RLY\?|YA RLY|NO WAI|OIC|MEBBE|WTF\?|OMG|OMGWTF|GTFO|IM IN YR|IM OUTTA YR|FOUND YR|YR|TIL|WILE|UPPIN|NERFIN|I IZ|HOW IZ I|IF U SAY SO|SRS|HAS A|LIEK(?: A)?|IZ)(?=\s|,|$)/,lookbehind:!0},/'Z(?=\s|,|$)/],"boolean":{pattern:/(^|\s)(?:WIN|FAIL)(?=\s|,|$)/,lookbehind:!0},variable:{pattern:/(^|\s)IT(?=\s|,|$)/,lookbehind:!0},operator:{pattern:/(^|\s)(?:NOT|BOTH SAEM|DIFFRINT|(?:SUM|DIFF|PRODUKT|QUOSHUNT|MOD|BIGGR|SMALLR|BOTH|EITHER|WON|ALL|ANY) OF)(?=\s|,|$)/,lookbehind:!0},punctuation:/\.{3}|\u2026|,|!/},Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[\s\S]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+\.?[a-f\d]*(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|\.?\d*(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,"function":/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/},Prism.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|.)*/,lookbehind:!0},string:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,builtin:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,symbol:{pattern:/^[^:=\r\n]+(?=\s*:(?!=))/m,inside:{variable:/\$+(?:[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:[/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,{pattern:/(\()(?:addsuffix|abspath|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:s|list)?)(?=[ \t])/,lookbehind:!0}],operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},code:[{pattern:/^(?: {4}|\t).+/m,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*(?:\r?\n|\r)(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])([\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*$|__$/}},italic:{pattern:/(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),Prism.languages.markdown.bold.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.italic.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.bold.inside.italic=Prism.util.clone(Prism.languages.markdown.italic),Prism.languages.markdown.italic.inside.bold=Prism.util.clone(Prism.languages.markdown.bold),Prism.languages.matlab={string:/\B'(?:''|[^'\n])*'/,comment:[/%\{[\s\S]*?\}%/,/%.+/],number:/\b-?(?:\d*\.?\d+(?:[eE][+-]?\d+)?(?:[ij])?|[ij])\b/,keyword:/\b(?:break|case|catch|continue|else|elseif|end|for|function|if|inf|NaN|otherwise|parfor|pause|pi|return|switch|try|while)\b/,"function":/(?!\d)\w+(?=\s*\()/,operator:/\.?[*^\/\\']|[+\-:@]|[<>=~]=?|&&?|\|\|?/,punctuation:/\.{3}|[.,;\[\](){}!]/},Prism.languages.mel={comment:/\/\/.*/,code:{pattern:/`(?:\\.|[^\\`\r\n])*`/,alias:"italic",inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"}}},string:/"(?:\\.|[^\\"\r\n])*"/,variable:/\$\w+/,number:/(?:\b|-)(?:0x[\da-fA-F]+|\d+\.?\d*)/,flag:{pattern:/-[^\d\W]\w*/,alias:"operator"},keyword:/\b(?:break|case|continue|default|do|else|float|for|global|if|in|int|matrix|proc|return|string|switch|vector|while)\b/, +"function":/\w+(?=\()|\b(?:about|abs|addAttr|addAttributeEditorNodeHelp|addDynamic|addNewShelfTab|addPP|addPanelCategory|addPrefixToName|advanceToNextDrivenKey|affectedNet|affects|aimConstraint|air|alias|aliasAttr|align|alignCtx|alignCurve|alignSurface|allViewFit|ambientLight|angle|angleBetween|animCone|animCurveEditor|animDisplay|animView|annotate|appendStringArray|applicationName|applyAttrPreset|applyTake|arcLenDimContext|arcLengthDimension|arclen|arrayMapper|art3dPaintCtx|artAttrCtx|artAttrPaintVertexCtx|artAttrSkinPaintCtx|artAttrTool|artBuildPaintMenu|artFluidAttrCtx|artPuttyCtx|artSelectCtx|artSetPaintCtx|artUserPaintCtx|assignCommand|assignInputDevice|assignViewportFactories|attachCurve|attachDeviceAttr|attachSurface|attrColorSliderGrp|attrCompatibility|attrControlGrp|attrEnumOptionMenu|attrEnumOptionMenuGrp|attrFieldGrp|attrFieldSliderGrp|attrNavigationControlGrp|attrPresetEditWin|attributeExists|attributeInfo|attributeMenu|attributeQuery|autoKeyframe|autoPlace|bakeClip|bakeFluidShading|bakePartialHistory|bakeResults|bakeSimulation|basename|basenameEx|batchRender|bessel|bevel|bevelPlus|binMembership|bindSkin|blend2|blendShape|blendShapeEditor|blendShapePanel|blendTwoAttr|blindDataType|boneLattice|boundary|boxDollyCtx|boxZoomCtx|bufferCurve|buildBookmarkMenu|buildKeyframeMenu|button|buttonManip|CBG|cacheFile|cacheFileCombine|cacheFileMerge|cacheFileTrack|camera|cameraView|canCreateManip|canvas|capitalizeString|catch|catchQuiet|ceil|changeSubdivComponentDisplayLevel|changeSubdivRegion|channelBox|character|characterMap|characterOutlineEditor|characterize|chdir|checkBox|checkBoxGrp|checkDefaultRenderGlobals|choice|circle|circularFillet|clamp|clear|clearCache|clip|clipEditor|clipEditorCurrentTimeCtx|clipSchedule|clipSchedulerOutliner|clipTrimBefore|closeCurve|closeSurface|cluster|cmdFileOutput|cmdScrollFieldExecuter|cmdScrollFieldReporter|cmdShell|coarsenSubdivSelectionList|collision|color|colorAtPoint|colorEditor|colorIndex|colorIndexSliderGrp|colorSliderButtonGrp|colorSliderGrp|columnLayout|commandEcho|commandLine|commandPort|compactHairSystem|componentEditor|compositingInterop|computePolysetVolume|condition|cone|confirmDialog|connectAttr|connectControl|connectDynamic|connectJoint|connectionInfo|constrain|constrainValue|constructionHistory|container|containsMultibyte|contextInfo|control|convertFromOldLayers|convertIffToPsd|convertLightmap|convertSolidTx|convertTessellation|convertUnit|copyArray|copyFlexor|copyKey|copySkinWeights|cos|cpButton|cpCache|cpClothSet|cpCollision|cpConstraint|cpConvClothToMesh|cpForces|cpGetSolverAttr|cpPanel|cpProperty|cpRigidCollisionFilter|cpSeam|cpSetEdit|cpSetSolverAttr|cpSolver|cpSolverTypes|cpTool|cpUpdateClothUVs|createDisplayLayer|createDrawCtx|createEditor|createLayeredPsdFile|createMotionField|createNewShelf|createNode|createRenderLayer|createSubdivRegion|cross|crossProduct|ctxAbort|ctxCompletion|ctxEditMode|ctxTraverse|currentCtx|currentTime|currentTimeCtx|currentUnit|curve|curveAddPtCtx|curveCVCtx|curveEPCtx|curveEditorCtx|curveIntersect|curveMoveEPCtx|curveOnSurface|curveSketchCtx|cutKey|cycleCheck|cylinder|dagPose|date|defaultLightListCheckBox|defaultNavigation|defineDataServer|defineVirtualDevice|deformer|deg_to_rad|delete|deleteAttr|deleteShadingGroupsAndMaterials|deleteShelfTab|deleteUI|deleteUnusedBrushes|delrandstr|detachCurve|detachDeviceAttr|detachSurface|deviceEditor|devicePanel|dgInfo|dgdirty|dgeval|dgtimer|dimWhen|directKeyCtx|directionalLight|dirmap|dirname|disable|disconnectAttr|disconnectJoint|diskCache|displacementToPoly|displayAffected|displayColor|displayCull|displayLevelOfDetail|displayPref|displayRGBColor|displaySmoothness|displayStats|displayString|displaySurface|distanceDimContext|distanceDimension|doBlur|dolly|dollyCtx|dopeSheetEditor|dot|dotProduct|doubleProfileBirailSurface|drag|dragAttrContext|draggerContext|dropoffLocator|duplicate|duplicateCurve|duplicateSurface|dynCache|dynControl|dynExport|dynExpression|dynGlobals|dynPaintEditor|dynParticleCtx|dynPref|dynRelEdPanel|dynRelEditor|dynamicLoad|editAttrLimits|editDisplayLayerGlobals|editDisplayLayerMembers|editRenderLayerAdjustment|editRenderLayerGlobals|editRenderLayerMembers|editor|editorTemplate|effector|emit|emitter|enableDevice|encodeString|endString|endsWith|env|equivalent|equivalentTol|erf|error|eval|evalDeferred|evalEcho|event|exactWorldBoundingBox|exclusiveLightCheckBox|exec|executeForEachObject|exists|exp|expression|expressionEditorListen|extendCurve|extendSurface|extrude|fcheck|fclose|feof|fflush|fgetline|fgetword|file|fileBrowserDialog|fileDialog|fileExtension|fileInfo|filetest|filletCurve|filter|filterCurve|filterExpand|filterStudioImport|findAllIntersections|findAnimCurves|findKeyframe|findMenuItem|findRelatedSkinCluster|finder|firstParentOf|fitBspline|flexor|floatEq|floatField|floatFieldGrp|floatScrollBar|floatSlider|floatSlider2|floatSliderButtonGrp|floatSliderGrp|floor|flow|fluidCacheInfo|fluidEmitter|fluidVoxelInfo|flushUndo|fmod|fontDialog|fopen|formLayout|format|fprint|frameLayout|fread|freeFormFillet|frewind|fromNativePath|fwrite|gamma|gauss|geometryConstraint|getApplicationVersionAsFloat|getAttr|getClassification|getDefaultBrush|getFileList|getFluidAttr|getInputDeviceRange|getMayaPanelTypes|getModifiers|getPanel|getParticleAttr|getPluginResource|getenv|getpid|glRender|glRenderEditor|globalStitch|gmatch|goal|gotoBindPose|grabColor|gradientControl|gradientControlNoAttr|graphDollyCtx|graphSelectContext|graphTrackCtx|gravity|grid|gridLayout|group|groupObjectsByName|HfAddAttractorToAS|HfAssignAS|HfBuildEqualMap|HfBuildFurFiles|HfBuildFurImages|HfCancelAFR|HfConnectASToHF|HfCreateAttractor|HfDeleteAS|HfEditAS|HfPerformCreateAS|HfRemoveAttractorFromAS|HfSelectAttached|HfSelectAttractors|HfUnAssignAS|hardenPointCurve|hardware|hardwareRenderPanel|headsUpDisplay|headsUpMessage|help|helpLine|hermite|hide|hilite|hitTest|hotBox|hotkey|hotkeyCheck|hsv_to_rgb|hudButton|hudSlider|hudSliderButton|hwReflectionMap|hwRender|hwRenderLoad|hyperGraph|hyperPanel|hyperShade|hypot|iconTextButton|iconTextCheckBox|iconTextRadioButton|iconTextRadioCollection|iconTextScrollList|iconTextStaticLabel|ikHandle|ikHandleCtx|ikHandleDisplayScale|ikSolver|ikSplineHandleCtx|ikSystem|ikSystemInfo|ikfkDisplayMethod|illustratorCurves|image|imfPlugins|inheritTransform|insertJoint|insertJointCtx|insertKeyCtx|insertKnotCurve|insertKnotSurface|instance|instanceable|instancer|intField|intFieldGrp|intScrollBar|intSlider|intSliderGrp|interToUI|internalVar|intersect|iprEngine|isAnimCurve|isConnected|isDirty|isParentOf|isSameObject|isTrue|isValidObjectName|isValidString|isValidUiName|isolateSelect|itemFilter|itemFilterAttr|itemFilterRender|itemFilterType|joint|jointCluster|jointCtx|jointDisplayScale|jointLattice|keyTangent|keyframe|keyframeOutliner|keyframeRegionCurrentTimeCtx|keyframeRegionDirectKeyCtx|keyframeRegionDollyCtx|keyframeRegionInsertKeyCtx|keyframeRegionMoveKeyCtx|keyframeRegionScaleKeyCtx|keyframeRegionSelectKeyCtx|keyframeRegionSetKeyCtx|keyframeRegionTrackCtx|keyframeStats|lassoContext|lattice|latticeDeformKeyCtx|launch|launchImageEditor|layerButton|layeredShaderPort|layeredTexturePort|layout|layoutDialog|lightList|lightListEditor|lightListPanel|lightlink|lineIntersection|linearPrecision|linstep|listAnimatable|listAttr|listCameras|listConnections|listDeviceAttachments|listHistory|listInputDeviceAxes|listInputDeviceButtons|listInputDevices|listMenuAnnotation|listNodeTypes|listPanelCategories|listRelatives|listSets|listTransforms|listUnselected|listerEditor|loadFluid|loadNewShelf|loadPlugin|loadPluginLanguageResources|loadPrefObjects|localizedPanelLabel|lockNode|loft|log|longNameOf|lookThru|ls|lsThroughFilter|lsType|lsUI|Mayatomr|mag|makeIdentity|makeLive|makePaintable|makeRoll|makeSingleSurface|makeTubeOn|makebot|manipMoveContext|manipMoveLimitsCtx|manipOptions|manipRotateContext|manipRotateLimitsCtx|manipScaleContext|manipScaleLimitsCtx|marker|match|max|memory|menu|menuBarLayout|menuEditor|menuItem|menuItemToShelf|menuSet|menuSetPref|messageLine|min|minimizeApp|mirrorJoint|modelCurrentTimeCtx|modelEditor|modelPanel|mouse|movIn|movOut|move|moveIKtoFK|moveKeyCtx|moveVertexAlongDirection|multiProfileBirailSurface|mute|nParticle|nameCommand|nameField|namespace|namespaceInfo|newPanelItems|newton|nodeCast|nodeIconButton|nodeOutliner|nodePreset|nodeType|noise|nonLinear|normalConstraint|normalize|nurbsBoolean|nurbsCopyUVSet|nurbsCube|nurbsEditUV|nurbsPlane|nurbsSelect|nurbsSquare|nurbsToPoly|nurbsToPolygonsPref|nurbsToSubdiv|nurbsToSubdivPref|nurbsUVSet|nurbsViewDirectionVector|objExists|objectCenter|objectLayer|objectType|objectTypeUI|obsoleteProc|oceanNurbsPreviewPlane|offsetCurve|offsetCurveOnSurface|offsetSurface|openGLExtension|openMayaPref|optionMenu|optionMenuGrp|optionVar|orbit|orbitCtx|orientConstraint|outlinerEditor|outlinerPanel|overrideModifier|paintEffectsDisplay|pairBlend|palettePort|paneLayout|panel|panelConfiguration|panelHistory|paramDimContext|paramDimension|paramLocator|parent|parentConstraint|particle|particleExists|particleInstancer|particleRenderInfo|partition|pasteKey|pathAnimation|pause|pclose|percent|performanceOptions|pfxstrokes|pickWalk|picture|pixelMove|planarSrf|plane|play|playbackOptions|playblast|plugAttr|plugNode|pluginInfo|pluginResourceUtil|pointConstraint|pointCurveConstraint|pointLight|pointMatrixMult|pointOnCurve|pointOnSurface|pointPosition|poleVectorConstraint|polyAppend|polyAppendFacetCtx|polyAppendVertex|polyAutoProjection|polyAverageNormal|polyAverageVertex|polyBevel|polyBlendColor|polyBlindData|polyBoolOp|polyBridgeEdge|polyCacheMonitor|polyCheck|polyChipOff|polyClipboard|polyCloseBorder|polyCollapseEdge|polyCollapseFacet|polyColorBlindData|polyColorDel|polyColorPerVertex|polyColorSet|polyCompare|polyCone|polyCopyUV|polyCrease|polyCreaseCtx|polyCreateFacet|polyCreateFacetCtx|polyCube|polyCut|polyCutCtx|polyCylinder|polyCylindricalProjection|polyDelEdge|polyDelFacet|polyDelVertex|polyDuplicateAndConnect|polyDuplicateEdge|polyEditUV|polyEditUVShell|polyEvaluate|polyExtrudeEdge|polyExtrudeFacet|polyExtrudeVertex|polyFlipEdge|polyFlipUV|polyForceUV|polyGeoSampler|polyHelix|polyInfo|polyInstallAction|polyLayoutUV|polyListComponentConversion|polyMapCut|polyMapDel|polyMapSew|polyMapSewMove|polyMergeEdge|polyMergeEdgeCtx|polyMergeFacet|polyMergeFacetCtx|polyMergeUV|polyMergeVertex|polyMirrorFace|polyMoveEdge|polyMoveFacet|polyMoveFacetUV|polyMoveUV|polyMoveVertex|polyNormal|polyNormalPerVertex|polyNormalizeUV|polyOptUvs|polyOptions|polyOutput|polyPipe|polyPlanarProjection|polyPlane|polyPlatonicSolid|polyPoke|polyPrimitive|polyPrism|polyProjection|polyPyramid|polyQuad|polyQueryBlindData|polyReduce|polySelect|polySelectConstraint|polySelectConstraintMonitor|polySelectCtx|polySelectEditCtx|polySeparate|polySetToFaceNormal|polySewEdge|polyShortestPathCtx|polySmooth|polySoftEdge|polySphere|polySphericalProjection|polySplit|polySplitCtx|polySplitEdge|polySplitRing|polySplitVertex|polyStraightenUVBorder|polySubdivideEdge|polySubdivideFacet|polyToSubdiv|polyTorus|polyTransfer|polyTriangulate|polyUVSet|polyUnite|polyWedgeFace|popen|popupMenu|pose|pow|preloadRefEd|print|progressBar|progressWindow|projFileViewer|projectCurve|projectTangent|projectionContext|projectionManip|promptDialog|propModCtx|propMove|psdChannelOutliner|psdEditTextureFile|psdExport|psdTextureFile|putenv|pwd|python|querySubdiv|quit|rad_to_deg|radial|radioButton|radioButtonGrp|radioCollection|radioMenuItemCollection|rampColorPort|rand|randomizeFollicles|randstate|rangeControl|readTake|rebuildCurve|rebuildSurface|recordAttr|recordDevice|redo|reference|referenceEdit|referenceQuery|refineSubdivSelectionList|refresh|refreshAE|registerPluginResource|rehash|reloadImage|removeJoint|removeMultiInstance|removePanelCategory|rename|renameAttr|renameSelectionList|renameUI|render|renderGlobalsNode|renderInfo|renderLayerButton|renderLayerParent|renderLayerPostProcess|renderLayerUnparent|renderManip|renderPartition|renderQualityNode|renderSettings|renderThumbnailUpdate|renderWindowEditor|renderWindowSelectContext|renderer|reorder|reorderDeformers|requires|reroot|resampleFluid|resetAE|resetPfxToPolyCamera|resetTool|resolutionNode|retarget|reverseCurve|reverseSurface|revolve|rgb_to_hsv|rigidBody|rigidSolver|roll|rollCtx|rootOf|rot|rotate|rotationInterpolation|roundConstantRadius|rowColumnLayout|rowLayout|runTimeCommand|runup|sampleImage|saveAllShelves|saveAttrPreset|saveFluid|saveImage|saveInitialState|saveMenu|savePrefObjects|savePrefs|saveShelf|saveToolSettings|scale|scaleBrushBrightness|scaleComponents|scaleConstraint|scaleKey|scaleKeyCtx|sceneEditor|sceneUIReplacement|scmh|scriptCtx|scriptEditorInfo|scriptJob|scriptNode|scriptTable|scriptToShelf|scriptedPanel|scriptedPanelType|scrollField|scrollLayout|sculpt|searchPathArray|seed|selLoadSettings|select|selectContext|selectCurveCV|selectKey|selectKeyCtx|selectKeyframeRegionCtx|selectMode|selectPref|selectPriority|selectType|selectedNodes|selectionConnection|separator|setAttr|setAttrEnumResource|setAttrMapping|setAttrNiceNameResource|setConstraintRestPosition|setDefaultShadingGroup|setDrivenKeyframe|setDynamic|setEditCtx|setEditor|setFluidAttr|setFocus|setInfinity|setInputDeviceMapping|setKeyCtx|setKeyPath|setKeyframe|setKeyframeBlendshapeTargetWts|setMenuMode|setNodeNiceNameResource|setNodeTypeFlag|setParent|setParticleAttr|setPfxToPolyCamera|setPluginResource|setProject|setStampDensity|setStartupMessage|setState|setToolTo|setUITemplate|setXformManip|sets|shadingConnection|shadingGeometryRelCtx|shadingLightRelCtx|shadingNetworkCompare|shadingNode|shapeCompare|shelfButton|shelfLayout|shelfTabLayout|shellField|shortNameOf|showHelp|showHidden|showManipCtx|showSelectionInTitle|showShadingGroupAttrEditor|showWindow|sign|simplify|sin|singleProfileBirailSurface|size|sizeBytes|skinCluster|skinPercent|smoothCurve|smoothTangentSurface|smoothstep|snap2to2|snapKey|snapMode|snapTogetherCtx|snapshot|soft|softMod|softModCtx|sort|sound|soundControl|source|spaceLocator|sphere|sphrand|spotLight|spotLightPreviewPort|spreadSheetEditor|spring|sqrt|squareSurface|srtContext|stackTrace|startString|startsWith|stitchAndExplodeShell|stitchSurface|stitchSurfacePoints|strcmp|stringArrayCatenate|stringArrayContains|stringArrayCount|stringArrayInsertAtIndex|stringArrayIntersector|stringArrayRemove|stringArrayRemoveAtIndex|stringArrayRemoveDuplicates|stringArrayRemoveExact|stringArrayToString|stringToStringArray|strip|stripPrefixFromName|stroke|subdAutoProjection|subdCleanTopology|subdCollapse|subdDuplicateAndConnect|subdEditUV|subdListComponentConversion|subdMapCut|subdMapSewMove|subdMatchTopology|subdMirror|subdToBlind|subdToPoly|subdTransferUVsToCache|subdiv|subdivCrease|subdivDisplaySmoothness|substitute|substituteAllString|substituteGeometry|substring|surface|surfaceSampler|surfaceShaderList|swatchDisplayPort|switchTable|symbolButton|symbolCheckBox|sysFile|system|tabLayout|tan|tangentConstraint|texLatticeDeformContext|texManipContext|texMoveContext|texMoveUVShellContext|texRotateContext|texScaleContext|texSelectContext|texSelectShortestPathCtx|texSmudgeUVContext|texWinToolCtx|text|textCurves|textField|textFieldButtonGrp|textFieldGrp|textManip|textScrollList|textToShelf|textureDisplacePlane|textureHairColor|texturePlacementContext|textureWindow|threadCount|threePointArcCtx|timeControl|timePort|timerX|toNativePath|toggle|toggleAxis|toggleWindowVisibility|tokenize|tokenizeList|tolerance|tolower|toolButton|toolCollection|toolDropped|toolHasOptions|toolPropertyWindow|torus|toupper|trace|track|trackCtx|transferAttributes|transformCompare|transformLimits|translator|trim|trunc|truncateFluidCache|truncateHairCache|tumble|tumbleCtx|turbulence|twoPointArcCtx|uiRes|uiTemplate|unassignInputDevice|undo|undoInfo|ungroup|uniform|unit|unloadPlugin|untangleUV|untitledFileName|untrim|upAxis|updateAE|userCtx|uvLink|uvSnapshot|validateShelfName|vectorize|view2dToolCtx|viewCamera|viewClipPlane|viewFit|viewHeadOn|viewLookAt|viewManip|viewPlace|viewSet|visor|volumeAxis|vortex|waitCursor|warning|webBrowser|webBrowserPrefs|whatIs|window|windowPref|wire|wireContext|workspace|wrinkle|wrinkleContext|writeTake|xbmLangPathList|xform)\b/,operator:[/\+[+=]?|-[-=]?|&&|\|\||[<>]=|[*\/!=]=?|[%^]/,{pattern:/(^|[^<])<(?!<)/,lookbehind:!0},{pattern:/(^|[^>])>(?!>)/,lookbehind:!0}],punctuation:/<<|>>|[.,:;?\[\](){}]/},Prism.languages.mel.code.inside.rest=Prism.util.clone(Prism.languages.mel),Prism.languages.mizar={comment:/::.+/,keyword:/@proof\b|\b(?:according|aggregate|all|and|antonym|are|as|associativity|assume|asymmetry|attr|be|begin|being|by|canceled|case|cases|clusters?|coherence|commutativity|compatibility|connectedness|consider|consistency|constructors|contradiction|correctness|def|deffunc|define|definitions?|defpred|do|does|equals|end|environ|ex|exactly|existence|for|from|func|given|hence|hereby|holds|idempotence|identity|iff?|implies|involutiveness|irreflexivity|is|it|let|means|mode|non|not|notations?|now|of|or|otherwise|over|per|pred|prefix|projectivity|proof|provided|qua|reconsider|redefine|reduce|reducibility|reflexivity|registrations?|requirements|reserve|sch|schemes?|section|selector|set|sethood|st|struct|such|suppose|symmetry|synonym|take|that|the|then|theorems?|thesis|thus|to|transitivity|uniqueness|vocabular(?:y|ies)|when|where|with|wrt)\b/,parameter:{pattern:/\$(?:10|\d)/,alias:"variable"},variable:/\w+(?=:)/,number:/(?:\b|-)\d+\b/,operator:/\.\.\.|->|&|\.?=/,punctuation:/\(#|#\)|[,:;\[\](){}]/},Prism.languages.monkey={string:/"[^"\r\n]*"/,comment:[/^#Rem\s+[\s\S]*?^#End/im,/'.+/],preprocessor:{pattern:/(^[ \t]*)#.+/m,lookbehind:!0,alias:"comment"},"function":/\w+(?=\()/,"type-char":{pattern:/(\w)[?%#$]/,lookbehind:!0,alias:"variable"},number:{pattern:/((?:\.\.)?)(?:(?:\b|\B-\.?|\B\.)\d+((?!\.\.)\.\d*)?|\$[\da-f]+)/i,lookbehind:!0},keyword:/\b(?:Void|Strict|Public|Private|Property|Bool|Int|Float|String|Array|Object|Continue|Exit|Import|Extern|New|Self|Super|Try|Catch|Eachin|True|False|Extends|Abstract|Final|Select|Case|Default|Const|Local|Global|Field|Method|Function|Class|End|If|Then|Else|ElseIf|EndIf|While|Wend|Repeat|Until|Forever|For|To|Step|Next|Return|Module|Interface|Implements|Inline|Throw|Null)\b/i,operator:/\.\.|<[=>]?|>=?|:?=|(?:[+\-*\/&~|]|\b(?:Mod|Shl|Shr)\b)=?|\b(?:And|Not|Or)\b/i,punctuation:/[.,:;()\[\]]/},Prism.languages.nasm={comment:/;.*$/m,string:/("|'|`)(\\?.)*?\1/m,label:{pattern:/(^\s*)[A-Za-z._?$][\w.?$@~#]*:/m,lookbehind:!0,alias:"function"},keyword:[/\[?BITS (16|32|64)\]?/m,{pattern:/(^\s*)section\s*[a-zA-Z\.]+:?/im,lookbehind:!0},/(?:extern|global)[^;\r\n]*/im,/(?:CPU|FLOAT|DEFAULT).*$/m],register:{pattern:/\b(?:st\d|[xyz]mm\d\d?|[cdt]r\d|r\d\d?[bwd]?|[er]?[abcd]x|[abcd][hl]|[er]?(bp|sp|si|di)|[cdefgs]s)\b/i,alias:"variable"},number:/(\b|-|(?=\$))(0[hx][\da-f]*\.?[\da-f]+(p[+-]?\d+)?|\d[\da-f]+[hx]|\$\d[\da-f]*|0[oq][0-7]+|[0-7]+[oq]|0[by][01]+|[01]+[by]|0[dt]\d+|\d*\.?\d+(\.?e[+-]?\d+)?[dt]?)\b/i,operator:/[\[\]*+\-\/%<>=&|$!]/},Prism.languages.nginx=Prism.languages.extend("clike",{comment:{pattern:/(^|[^"{\\])#.*/,lookbehind:!0},keyword:/\b(?:CONTENT_|DOCUMENT_|GATEWAY_|HTTP_|HTTPS|if_not_empty|PATH_|QUERY_|REDIRECT_|REMOTE_|REQUEST_|SCGI|SCRIPT_|SERVER_|http|server|events|location|include|accept_mutex|accept_mutex_delay|access_log|add_after_body|add_before_body|add_header|addition_types|aio|alias|allow|ancient_browser|ancient_browser_value|auth|auth_basic|auth_basic_user_file|auth_http|auth_http_header|auth_http_timeout|autoindex|autoindex_exact_size|autoindex_localtime|break|charset|charset_map|charset_types|chunked_transfer_encoding|client_body_buffer_size|client_body_in_file_only|client_body_in_single_buffer|client_body_temp_path|client_body_timeout|client_header_buffer_size|client_header_timeout|client_max_body_size|connection_pool_size|create_full_put_path|daemon|dav_access|dav_methods|debug_connection|debug_points|default_type|deny|devpoll_changes|devpoll_events|directio|directio_alignment|disable_symlinks|empty_gif|env|epoll_events|error_log|error_page|expires|fastcgi_buffer_size|fastcgi_buffers|fastcgi_busy_buffers_size|fastcgi_cache|fastcgi_cache_bypass|fastcgi_cache_key|fastcgi_cache_lock|fastcgi_cache_lock_timeout|fastcgi_cache_methods|fastcgi_cache_min_uses|fastcgi_cache_path|fastcgi_cache_purge|fastcgi_cache_use_stale|fastcgi_cache_valid|fastcgi_connect_timeout|fastcgi_hide_header|fastcgi_ignore_client_abort|fastcgi_ignore_headers|fastcgi_index|fastcgi_intercept_errors|fastcgi_keep_conn|fastcgi_max_temp_file_size|fastcgi_next_upstream|fastcgi_no_cache|fastcgi_param|fastcgi_pass|fastcgi_pass_header|fastcgi_read_timeout|fastcgi_redirect_errors|fastcgi_send_timeout|fastcgi_split_path_info|fastcgi_store|fastcgi_store_access|fastcgi_temp_file_write_size|fastcgi_temp_path|flv|geo|geoip_city|geoip_country|google_perftools_profiles|gzip|gzip_buffers|gzip_comp_level|gzip_disable|gzip_http_version|gzip_min_length|gzip_proxied|gzip_static|gzip_types|gzip_vary|if|if_modified_since|ignore_invalid_headers|image_filter|image_filter_buffer|image_filter_jpeg_quality|image_filter_sharpen|image_filter_transparency|imap_capabilities|imap_client_buffer|include|index|internal|ip_hash|keepalive|keepalive_disable|keepalive_requests|keepalive_timeout|kqueue_changes|kqueue_events|large_client_header_buffers|limit_conn|limit_conn_log_level|limit_conn_zone|limit_except|limit_rate|limit_rate_after|limit_req|limit_req_log_level|limit_req_zone|limit_zone|lingering_close|lingering_time|lingering_timeout|listen|location|lock_file|log_format|log_format_combined|log_not_found|log_subrequest|map|map_hash_bucket_size|map_hash_max_size|master_process|max_ranges|memcached_buffer_size|memcached_connect_timeout|memcached_next_upstream|memcached_pass|memcached_read_timeout|memcached_send_timeout|merge_slashes|min_delete_depth|modern_browser|modern_browser_value|mp4|mp4_buffer_size|mp4_max_buffer_size|msie_padding|msie_refresh|multi_accept|open_file_cache|open_file_cache_errors|open_file_cache_min_uses|open_file_cache_valid|open_log_file_cache|optimize_server_names|override_charset|pcre_jit|perl|perl_modules|perl_require|perl_set|pid|pop3_auth|pop3_capabilities|port_in_redirect|post_action|postpone_output|protocol|proxy|proxy_buffer|proxy_buffer_size|proxy_buffering|proxy_buffers|proxy_busy_buffers_size|proxy_cache|proxy_cache_bypass|proxy_cache_key|proxy_cache_lock|proxy_cache_lock_timeout|proxy_cache_methods|proxy_cache_min_uses|proxy_cache_path|proxy_cache_use_stale|proxy_cache_valid|proxy_connect_timeout|proxy_cookie_domain|proxy_cookie_path|proxy_headers_hash_bucket_size|proxy_headers_hash_max_size|proxy_hide_header|proxy_http_version|proxy_ignore_client_abort|proxy_ignore_headers|proxy_intercept_errors|proxy_max_temp_file_size|proxy_method|proxy_next_upstream|proxy_no_cache|proxy_pass|proxy_pass_error_message|proxy_pass_header|proxy_pass_request_body|proxy_pass_request_headers|proxy_read_timeout|proxy_redirect|proxy_redirect_errors|proxy_send_lowat|proxy_send_timeout|proxy_set_body|proxy_set_header|proxy_ssl_session_reuse|proxy_store|proxy_store_access|proxy_temp_file_write_size|proxy_temp_path|proxy_timeout|proxy_upstream_fail_timeout|proxy_upstream_max_fails|random_index|read_ahead|real_ip_header|recursive_error_pages|request_pool_size|reset_timedout_connection|resolver|resolver_timeout|return|rewrite|root|rtsig_overflow_events|rtsig_overflow_test|rtsig_overflow_threshold|rtsig_signo|satisfy|satisfy_any|secure_link_secret|send_lowat|send_timeout|sendfile|sendfile_max_chunk|server|server_name|server_name_in_redirect|server_names_hash_bucket_size|server_names_hash_max_size|server_tokens|set|set_real_ip_from|smtp_auth|smtp_capabilities|so_keepalive|source_charset|split_clients|ssi|ssi_silent_errors|ssi_types|ssi_value_length|ssl|ssl_certificate|ssl_certificate_key|ssl_ciphers|ssl_client_certificate|ssl_crl|ssl_dhparam|ssl_engine|ssl_prefer_server_ciphers|ssl_protocols|ssl_session_cache|ssl_session_timeout|ssl_verify_client|ssl_verify_depth|starttls|stub_status|sub_filter|sub_filter_once|sub_filter_types|tcp_nodelay|tcp_nopush|timeout|timer_resolution|try_files|types|types_hash_bucket_size|types_hash_max_size|underscores_in_headers|uninitialized_variable_warn|upstream|use|user|userid|userid_domain|userid_expires|userid_name|userid_p3p|userid_path|userid_service|valid_referers|variables_hash_bucket_size|variables_hash_max_size|worker_connections|worker_cpu_affinity|worker_priority|worker_processes|worker_rlimit_core|worker_rlimit_nofile|worker_rlimit_sigpending|working_directory|xclient|xml_entities|xslt_entities|xslt_stylesheet|xslt_types)\b/i}),Prism.languages.insertBefore("nginx","keyword",{variable:/\$[a-z_]+/i}),Prism.languages.nim={comment:/#.*/,string:/(?:(?:\b(?!\d)(?:\w|\\x[8-9a-fA-F][0-9a-fA-F])+)?(?:"""[\s\S]*?"""(?!")|"(?:\\[\s\S]|""|[^"\\])*")|'(?:\\(?:\d+|x[\da-fA-F]{2}|.)|[^'])')/,number:/\b(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:(?!\.\.)\.[\d_]*)?(?:[eE][+-]?\d[\d_]*)?)(?:'?[iuf]\d*)?/,keyword:/\b(?:addr|as|asm|atomic|bind|block|break|case|cast|concept|const|continue|converter|defer|discard|distinct|do|elif|else|end|enum|except|export|finally|for|from|func|generic|if|import|include|interface|iterator|let|macro|method|mixin|nil|object|out|proc|ptr|raise|ref|return|static|template|try|tuple|type|using|var|when|while|with|without|yield)\b/,"function":{pattern:/(?:(?!\d)(?:\w|\\x[8-9a-fA-F][0-9a-fA-F])+|`[^`\r\n]+`)\*?(?:\[[^\]]+\])?(?=\s*\()/,inside:{operator:/\*$/}},ignore:{pattern:/`[^`\r\n]+`/,inside:{punctuation:/`/}},operator:{pattern:/(^|[({\[](?=\.\.)|(?![({\[]\.).)(?:(?:[=+\-*\/<>@$~&%|!?^:\\]|\.\.|\.(?![)}\]]))+|\b(?:and|div|of|or|in|is|isnot|mod|not|notin|shl|shr|xor)\b)/m,lookbehind:!0},punctuation:/[({\[]\.|\.[)}\]]|[`(){}\[\],:]/},Prism.languages.nix={comment:/\/\*[\s\S]*?\*\/|#.*/,string:{pattern:/"(?:[^"\\]|\\[\s\S])*"|''(?:(?!'')[\s\S]|''(?:'|\\|\$\{))*''/,inside:{interpolation:{pattern:/(^|(?:^|(?!'').)[^\\])\$\{(?:[^}]|\{[^}]*\})*}/,lookbehind:!0,inside:{antiquotation:{pattern:/^\$(?=\{)/,alias:"variable"}}}}},url:[/\b(?:[a-z]{3,7}:\/\/)[\w\-+%~\/.:#=?&]+/,{pattern:/([^\/])(?:[\w\-+%~.:#=?&]*(?!\/\/)[\w\-+%~\/.:#=?&])?(?!\/\/)\/[\w\-+%~\/.:#=?&]*/,lookbehind:!0}],antiquotation:{pattern:/\$(?=\{)/,alias:"variable"},number:/\b\d+\b/,keyword:/\b(?:assert|builtins|else|if|in|inherit|let|null|or|then|with)\b/,"function":/\b(?:abort|add|all|any|attrNames|attrValues|baseNameOf|compareVersions|concatLists|currentSystem|deepSeq|derivation|dirOf|div|elem(?:At)?|fetch(?:url|Tarball)|filter(?:Source)?|fromJSON|genList|getAttr|getEnv|hasAttr|hashString|head|import|intersectAttrs|is(?:Attrs|Bool|Function|Int|List|Null|String)|length|lessThan|listToAttrs|map|mul|parseDrvName|pathExists|read(?:Dir|File)|removeAttrs|replaceStrings|seq|sort|stringLength|sub(?:string)?|tail|throw|to(?:File|JSON|Path|String|XML)|trace|typeOf)\b|\bfoldl'\B/,"boolean":/\b(?:true|false)\b/,operator:/[=!<>]=?|\+\+?|\|\||&&|\/\/|->?|[?@]/,punctuation:/[{}()[\].,:;]/},Prism.languages.nix.string.inside.interpolation.inside.rest=Prism.util.clone(Prism.languages.nix),Prism.languages.nsis={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|[#;].*)/,lookbehind:!0},string:/("|')(\\?.)*?\1/,keyword:/\b(Abort|Add(BrandingImage|Size)|AdvSplash|Allow(RootDirInstall|SkipFiles)|AutoCloseWindow|Banner|BG(Font|Gradient|Image)|BrandingText|BringToFront|Call(InstDLL)?|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|Create(Directory|Font|ShortCut)|Delete(INISec|INIStr|RegKey|RegValue)?|Detail(Print|sButtonText)|Dialer|Dir(Text|Var|Verify)|EnableWindow|Enum(RegKey|RegValue)|Exch|Exec(Shell|Wait)?|ExpandEnvStrings|File(BufSize|Close|ErrorText|Open|Read|ReadByte|ReadUTF16LE|ReadWord|WriteUTF16LE|Seek|Write|WriteByte|WriteWord)?|Find(Close|First|Next|Window)|FlushINI|Get(CurInstType|CurrentAddress|DlgItem|DLLVersion(Local)?|ErrorLevel|FileTime(Local)?|FullPathName|Function(Address|End)?|InstDirError|LabelAddress|TempFileName)|Goto|HideWindow|Icon|If(Abort|Errors|FileExists|RebootFlag|Silent)|InitPluginsDir|Install(ButtonText|Colors|Dir(RegKey)?)|InstProgressFlags|Inst(Type(GetText|SetText)?)|Int(CmpU?|Fmt|Op)|IsWindow|Lang(DLL|String)|License(BkColor|Data|ForceSelection|LangString|Text)|LoadLanguageFile|LockWindow|Log(Set|Text)|Manifest(DPIAware|SupportedOS)|Math|MessageBox|MiscButtonText|Name|Nop|ns(Dialogs|Exec)|NSISdl|OutFile|Page(Callbacks)?|Pop|Push|Quit|Read(EnvStr|INIStr|RegDWORD|RegStr)|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|Section(End|GetFlags|GetInstTypes|GetSize|GetText|Group|In|SetFlags|SetInstTypes|SetSize|SetText)?|SendMessage|Set(AutoClose|BrandingImage|Compress|Compressor(DictSize)?|CtlColors|CurInstType|DatablockOptimize|DateSave|Details(Print|View)|ErrorLevel|Errors|FileAttributes|Font|OutPath|Overwrite|PluginUnload|RebootFlag|RegView|ShellVarContext|Silent)|Show(InstDetails|UninstDetails|Window)|Silent(Install|UnInstall)|Sleep|SpaceTexts|Splash|StartMenu|Str(CmpS?|Cpy|Len)|SubCaption|System|Unicode|Uninstall(ButtonText|Caption|Icon|SubCaption|Text)|UninstPage|UnRegDLL|UserInfo|Var|VI(AddVersionKey|FileVersion|ProductVersion)|VPatch|WindowIcon|Write(INIStr|RegBin|RegDWORD|RegExpandStr|RegStr|Uninstaller)|XPStyle)\b/,property:/\b(admin|all|auto|both|colored|false|force|hide|highest|lastused|leave|listonly|none|normal|notset|off|on|open|print|show|silent|silentlog|smooth|textonly|true|user|ARCHIVE|FILE_(ATTRIBUTE_ARCHIVE|ATTRIBUTE_NORMAL|ATTRIBUTE_OFFLINE|ATTRIBUTE_READONLY|ATTRIBUTE_SYSTEM|ATTRIBUTE_TEMPORARY)|HK(CR|CU|DD|LM|PD|U)|HKEY_(CLASSES_ROOT|CURRENT_CONFIG|CURRENT_USER|DYN_DATA|LOCAL_MACHINE|PERFORMANCE_DATA|USERS)|ID(ABORT|CANCEL|IGNORE|NO|OK|RETRY|YES)|MB_(ABORTRETRYIGNORE|DEFBUTTON1|DEFBUTTON2|DEFBUTTON3|DEFBUTTON4|ICONEXCLAMATION|ICONINFORMATION|ICONQUESTION|ICONSTOP|OK|OKCANCEL|RETRYCANCEL|RIGHT|RTLREADING|SETFOREGROUND|TOPMOST|USERICON|YESNO)|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SYSTEM|TEMPORARY)\b/,variable:/\$[({]?[-_\w]+[)}]?/i,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,operator:/--?|\+\+?|<=?|>=?|==?=?|&&?|\|?\||[?*\/~^%]/,punctuation:/[{}[\];(),.:]/,important:/!(addincludedir|addplugindir|appendfile|cd|define|delfile|echo|else|endif|error|execute|finalize|getdllversionsystem|ifdef|ifmacrodef|ifmacrondef|ifndef|if|include|insertmacro|macroend|macro|makensis|packhdr|searchparse|searchreplace|tempfile|undef|verbose|warning)\b/i},Prism.languages.objectivec=Prism.languages.extend("c",{keyword:/\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while|in|self|super)\b|(@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,string:/("|')(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|@"(\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,operator:/-[->]?|\+\+?|!=?|<>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),Prism.languages.ocaml={comment:/\(\*[\s\S]*?\*\)/,string:[/"(?:\\.|[^\\\r\n"])*"/,/(['`])(?:\\(?:\d+|x[\da-f]+|.)|(?!\1)[^\\\r\n])\1/i],number:/\b-?(?:0x[\da-f][\da-f_]+|(?:0[bo])?\d[\d_]*\.?[\d_]*(?:e[+-]?[\d_]+)?)/i,type:{pattern:/\B['`][a-z\d_]*/i,alias:"variable"},directive:{pattern:/\B#[a-z\d_]+/i,alias:"function"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|object|of|open|prefix|private|rec|then|sig|struct|to|try|type|val|value|virtual|where|while|with)\b/,"boolean":/\b(?:false|true)\b/,operator:/:=|[=<>@^|&+\-*\/$%!?~][!$%&\*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lxor|lsl|lsr|mod|nor|or)\b/,punctuation:/[(){}\[\]|_.,:;]/},Prism.languages.oz={comment:/\/\*[\s\S]*?\*\/|%.*/,string:/"(?:[^"\\]|\\[\s\S])*"/,atom:{pattern:/'(?:[^'\\]|\\.)*'/,alias:"builtin"},keyword:/[$_]|\[\]|\b(?:at|attr|case|catch|choice|class|cond|declare|define|dis|else(?:case|if)?|end|export|fail|false|feat|finally|from|fun|functor|if|import|in|local|lock|meth|nil|not|of|or|prepare|proc|prop|raise|require|self|skip|then|thread|true|try|unit)\b/,"function":[/[a-z][A-Za-z\d]*(?=\()/,{pattern:/(\{)[A-Z][A-Za-z\d]*/,lookbehind:!0}],number:/\b(?:0[bx][\da-f]+|\d+\.?\d*(?:e~?\d+)?\b)|&(?:[^\\]|\\(?:\d{3}|.))/i,variable:/\b[A-Z][A-Za-z\d]*|`(?:[^`\\]|\\.)+`/,"attr-name":/\w+(?=:)/,operator:/:(?:=|::?)|<[-:=]?|=(?:=|=?:?|\\=:?|!!?|[|#+\-*\/,~^@]|\b(?:andthen|div|mod|orelse)\b/,punctuation:/[\[\](){}.:;?]/},Prism.languages.parigp={comment:/\/\*[\s\S]*?\*\/|\\\\.*/,string:/"(?:[^"\\]|\\.)*"/,keyword:function(){var e=["breakpoint","break","dbg_down","dbg_err","dbg_up","dbg_x","forcomposite","fordiv","forell","forpart","forprime","forstep","forsubgroup","forvec","for","iferr","if","local","my","next","return","until","while"] +;return e=e.map(function(e){return e.split("").join(" *")}).join("|"),RegExp("\\b(?:"+e+")\\b")}(),"function":/\w[\w ]*?(?= *\()/,number:{pattern:/((?:\. *\. *)?)(?:\d(?: *\d)*(?: *(?!\. *\.)\.(?: *\d)*)?|\. *\d(?: *\d)*)(?: *e *[+-]? *\d(?: *\d)*)?/i,lookbehind:!0},operator:/\. *\.|[*\/!](?: *=)?|%(?: *=|(?: *#)?(?: *')*)?|\+(?: *[+=])?|-(?: *[-=>])?|<(?:(?: *<)?(?: *=)?| *>)?|>(?: *>)?(?: *=)?|=(?: *=){0,2}|\\(?: *\/)?(?: *=)?|&(?: *&)?|\| *\||['#~^]/,punctuation:/[\[\]{}().,:;|]/},Prism.languages.parser=Prism.languages.extend("markup",{keyword:{pattern:/(^|[^^])(?:\^(?:case|eval|for|if|switch|throw)\b|@(?:BASE|CLASS|GET(?:_DEFAULT)?|OPTIONS|SET_DEFAULT|USE)\b)/,lookbehind:!0},variable:{pattern:/(^|[^^])\B\$(?:\w+|(?=[.\{]))(?:(?:\.|::?)\w+)*(?:\.|::?)?/,lookbehind:!0,inside:{punctuation:/\.|:+/}},"function":{pattern:/(^|[^^])\B[@^]\w+(?:(?:\.|::?)\w+)*(?:\.|::?)?/,lookbehind:!0,inside:{keyword:{pattern:/(^@)(?:GET_|SET_)/,lookbehind:!0},punctuation:/\.|:+/}},escape:{pattern:/\^(?:[$^;@()\[\]{}"':]|#[a-f\d]*)/i,alias:"builtin"},punctuation:/[\[\](){};]/}),Prism.languages.insertBefore("parser","keyword",{"parser-comment":{pattern:/(\s)#.*/,lookbehind:!0,alias:"comment"},expression:{pattern:/(^|[^^])\((?:[^()]|\((?:[^()]|\((?:[^()])*\))*\))*\)/,lookbehind:!0,inside:{string:{pattern:/(^|[^^])(["'])(?:(?!\2)[^^]|\^[\s\S])*\2/,lookbehind:!0},keyword:Prism.languages.parser.keyword,variable:Prism.languages.parser.variable,"function":Prism.languages.parser["function"],"boolean":/\b(?:true|false)\b/,number:/\b(?:0x[a-f\d]+|\d+\.?\d*(?:e[+-]?\d+)?)\b/i,escape:Prism.languages.parser.escape,operator:/[~+*\/\\%]|!(?:\|\|?|=)?|&&?|\|\|?|==|<[<=]?|>[>=]?|-[fd]?|\b(?:def|eq|ge|gt|in|is|le|lt|ne)\b/,punctuation:Prism.languages.parser.punctuation}}}),Prism.languages.insertBefore("inside","punctuation",{expression:Prism.languages.parser.expression,keyword:Prism.languages.parser.keyword,variable:Prism.languages.parser.variable,"function":Prism.languages.parser["function"],escape:Prism.languages.parser.escape,"parser-punctuation":{pattern:Prism.languages.parser.punctuation,alias:"punctuation"}},Prism.languages.parser.tag.inside["attr-value"]),Prism.languages.pascal={comment:[/\(\*[\s\S]+?\*\)/,/\{[\s\S]+?\}/,/\/\/.*/],string:/(?:'(?:''|[^'\r\n])*'|#[&$%]?[a-f\d]+)+|\^[a-z]/i,keyword:[{pattern:/(^|[^&])\b(?:absolute|array|asm|begin|case|const|constructor|destructor|do|downto|else|end|file|for|function|goto|if|implementation|inherited|inline|interface|label|nil|object|of|operator|packed|procedure|program|record|reintroduce|repeat|self|set|string|then|to|type|unit|until|uses|var|while|with)\b/i,lookbehind:!0},{pattern:/(^|[^&])\b(?:dispose|exit|false|new|true)\b/i,lookbehind:!0},{pattern:/(^|[^&])\b(?:class|dispinterface|except|exports|finalization|finally|initialization|inline|library|on|out|packed|property|raise|resourcestring|threadvar|try)\b/i,lookbehind:!0},{pattern:/(^|[^&])\b(?:absolute|abstract|alias|assembler|bitpacked|break|cdecl|continue|cppdecl|cvar|default|deprecated|dynamic|enumerator|experimental|export|external|far|far16|forward|generic|helper|implements|index|interrupt|iochecks|local|message|name|near|nodefault|noreturn|nostackframe|oldfpccall|otherwise|overload|override|pascal|platform|private|protected|public|published|read|register|reintroduce|result|safecall|saveregisters|softfloat|specialize|static|stdcall|stored|strict|unaligned|unimplemented|varargs|virtual|write)\b/i,lookbehind:!0}],number:[/[+-]?(?:[&%]\d+|\$[a-f\d]+)/i,/([+-]|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?/i],operator:[/\.\.|\*\*|:=|<[<=>]?|>[>=]?|[+\-*\/]=?|[@^=]/i,{pattern:/(^|[^&])\b(?:and|as|div|exclude|in|include|is|mod|not|or|shl|shr|xor)\b/,lookbehind:!0}],punctuation:/\(\.|\.\)|[()\[\]:;,.]/},Prism.languages.perl={comment:[{pattern:/(^\s*)=\w+[\s\S]*?=cut.*/m,lookbehind:!0},{pattern:/(^|[^\\$])#.*/,lookbehind:!0}],string:[/\b(?:q|qq|qx|qw)\s*([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1/,/\b(?:q|qq|qx|qw)\s+([a-zA-Z0-9])(?:[^\\]|\\[\s\S])*?\1/,/\b(?:q|qq|qx|qw)\s*\((?:[^()\\]|\\[\s\S])*\)/,/\b(?:q|qq|qx|qw)\s*\{(?:[^{}\\]|\\[\s\S])*\}/,/\b(?:q|qq|qx|qw)\s*\[(?:[^[\]\\]|\\[\s\S])*\]/,/\b(?:q|qq|qx|qw)\s*<(?:[^<>\\]|\\[\s\S])*>/,/("|`)(?:[^\\]|\\[\s\S])*?\1/,/'(?:[^'\\\r\n]|\\.)*'/],regex:[/\b(?:m|qr)\s*([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1[msixpodualngc]*/,/\b(?:m|qr)\s+([a-zA-Z0-9])(?:[^\\]|\\.)*?\1[msixpodualngc]*/,/\b(?:m|qr)\s*\((?:[^()\\]|\\[\s\S])*\)[msixpodualngc]*/,/\b(?:m|qr)\s*\{(?:[^{}\\]|\\[\s\S])*\}[msixpodualngc]*/,/\b(?:m|qr)\s*\[(?:[^[\]\\]|\\[\s\S])*\][msixpodualngc]*/,/\b(?:m|qr)\s*<(?:[^<>\\]|\\[\s\S])*>[msixpodualngc]*/,{pattern:/(^|[^-]\b)(?:s|tr|y)\s*([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\2(?:[^\\]|\\[\s\S])*?\2[msixpodualngcer]*/,lookbehind:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s+([a-zA-Z0-9])(?:[^\\]|\\[\s\S])*?\2(?:[^\\]|\\[\s\S])*?\2[msixpodualngcer]*/,lookbehind:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*\((?:[^()\\]|\\[\s\S])*\)\s*\((?:[^()\\]|\\[\s\S])*\)[msixpodualngcer]*/,lookbehind:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*\{(?:[^{}\\]|\\[\s\S])*\}\s*\{(?:[^{}\\]|\\[\s\S])*\}[msixpodualngcer]*/,lookbehind:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*\[(?:[^[\]\\]|\\[\s\S])*\]\s*\[(?:[^[\]\\]|\\[\s\S])*\][msixpodualngcer]*/,lookbehind:!0},{pattern:/(^|[^-]\b)(?:s|tr|y)\s*<(?:[^<>\\]|\\[\s\S])*>\s*<(?:[^<>\\]|\\[\s\S])*>[msixpodualngcer]*/,lookbehind:!0},/\/(?:[^\/\\\r\n]|\\.)*\/[msixpodualngc]*(?=\s*(?:$|[\r\n,.;})&|\-+*~<>!?^]|(lt|gt|le|ge|eq|ne|cmp|not|and|or|xor|x)\b))/],variable:[/[&*$@%]\{\^[A-Z]+\}/,/[&*$@%]\^[A-Z_]/,/[&*$@%]#?(?=\{)/,/[&*$@%]#?((::)*'?(?!\d)[\w$]+)+(::)*/i,/[&*$@%]\d+/,/(?!%=)[$@%][!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~]/],filehandle:{pattern:/<(?![<=])\S*>|\b_\b/,alias:"symbol"},vstring:{pattern:/v\d+(\.\d+)*|\d+(\.\d+){2,}/,alias:"string"},"function":{pattern:/sub [a-z0-9_]+/i,inside:{keyword:/sub/}},keyword:/\b(any|break|continue|default|delete|die|do|else|elsif|eval|for|foreach|given|goto|if|last|local|my|next|our|package|print|redo|require|say|state|sub|switch|undef|unless|until|use|when|while)\b/,number:/\b-?(0x[\dA-Fa-f](_?[\dA-Fa-f])*|0b[01](_?[01])*|(\d(_?\d)*)?\.?\d(_?\d)*([Ee][+-]?\d+)?)\b/,operator:/-[rwxoRWXOezsfdlpSbctugkTBMAC]\b|\+[+=]?|-[-=>]?|\*\*?=?|\/\/?=?|=[=~>]?|~[~=]?|\|\|?=?|&&?=?|<(?:=>?|<=?)?|>>?=?|![~=]?|[%^]=?|\.(?:=|\.\.?)?|[\\?]|\bx(?:=|\b)|\b(lt|gt|le|ge|eq|ne|cmp|not|and|or|xor)\b/,punctuation:/[{}[\];(),:]/},Prism.languages.php=Prism.languages.extend("clike",{keyword:/\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/i,constant:/\b[A-Z0-9_]{2,}\b/,comment:{pattern:/(^|[^\\])(?:\/\*[\w\W]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0}}),Prism.languages.insertBefore("php","class-name",{"shell-comment":{pattern:/(^|[^\\])#.*/,lookbehind:!0,alias:"comment"}}),Prism.languages.insertBefore("php","keyword",{delimiter:/\?>|<\?(?:php)?/i,variable:/\$\w+\b/i,"package":{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),Prism.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}}),Prism.languages.markup&&(Prism.hooks.add("before-highlight",function(t){"php"===t.language&&(t.tokenStack=[],t.code=t.code.replace(/(?:<\?php|<\?)[\w\W]*?(?:\?>)/gi,function(e){return t.tokenStack.push(e),"{{{PHP"+t.tokenStack.length+"}}}"}))}),Prism.hooks.add("after-highlight",function(e){if("php"===e.language){for(var t,n=0;t=e.tokenStack[n];n++)e.highlightedCode=e.highlightedCode.replace("{{{PHP"+(n+1)+"}}}",Prism.highlight(t,e.grammar,"php").replace(/\$/g,"$$$$"));e.element.innerHTML=e.highlightedCode}}),Prism.hooks.add("wrap",function(e){"php"===e.language&&"markup"===e.type&&(e.content=e.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g,'$1'))}),Prism.languages.insertBefore("php","comment",{markup:{pattern:/<[^?]\/?(.*?)>/,inside:Prism.languages.markup},php:/\{\{\{PHP[0-9]+\}\}\}/})),Prism.languages.insertBefore("php","variable",{"this":/\$this\b/,global:/\$(?:_(?:SERVER|GET|POST|FILES|REQUEST|SESSION|ENV|COOKIE)|GLOBALS|HTTP_RAW_POST_DATA|argc|argv|php_errormsg|http_response_header)/,scope:{pattern:/\b[\w\\]+::/,inside:{keyword:/(static|self|parent)/,punctuation:/(::|\\)/}}}),Prism.languages.powershell={comment:[{pattern:/(^|[^`])<#[\w\W]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(`?[\w\W])*?"/,greedy:!0,inside:{"function":{pattern:/[^`]\$\(.*?\)/,inside:{}}}},{pattern:/'([^']|'')*'/,greedy:!0}],namespace:/\[[a-z][\w\W]*?\]/i,"boolean":/\$(true|false)\b/i,variable:/\$\w+\b/i,"function":[/\b(Add-(Computer|Content|History|Member|PSSnapin|Type)|Checkpoint-Computer|Clear-(Content|EventLog|History|Item|ItemProperty|Variable)|Compare-Object|Complete-Transaction|Connect-PSSession|ConvertFrom-(Csv|Json|StringData)|Convert-Path|ConvertTo-(Csv|Html|Json|Xml)|Copy-(Item|ItemProperty)|Debug-Process|Disable-(ComputerRestore|PSBreakpoint|PSRemoting|PSSessionConfiguration)|Disconnect-PSSession|Enable-(ComputerRestore|PSBreakpoint|PSRemoting|PSSessionConfiguration)|Enter-PSSession|Exit-PSSession|Export-(Alias|Clixml|Console|Csv|FormatData|ModuleMember|PSSession)|ForEach-Object|Format-(Custom|List|Table|Wide)|Get-(Alias|ChildItem|Command|ComputerRestorePoint|Content|ControlPanelItem|Culture|Date|Event|EventLog|EventSubscriber|FormatData|Help|History|Host|HotFix|Item|ItemProperty|Job|Location|Member|Module|Process|PSBreakpoint|PSCallStack|PSDrive|PSProvider|PSSession|PSSessionConfiguration|PSSnapin|Random|Service|TraceSource|Transaction|TypeData|UICulture|Unique|Variable|WmiObject)|Group-Object|Import-(Alias|Clixml|Csv|LocalizedData|Module|PSSession)|Invoke-(Command|Expression|History|Item|RestMethod|WebRequest|WmiMethod)|Join-Path|Limit-EventLog|Measure-(Command|Object)|Move-(Item|ItemProperty)|New-(Alias|Event|EventLog|Item|ItemProperty|Module|ModuleManifest|Object|PSDrive|PSSession|PSSessionConfigurationFile|PSSessionOption|PSTransportOption|Service|TimeSpan|Variable|WebServiceProxy)|Out-(Default|File|GridView|Host|Null|Printer|String)|Pop-Location|Push-Location|Read-Host|Receive-(Job|PSSession)|Register-(EngineEvent|ObjectEvent|PSSessionConfiguration|WmiEvent)|Remove-(Computer|Event|EventLog|Item|ItemProperty|Job|Module|PSBreakpoint|PSDrive|PSSession|PSSnapin|TypeData|Variable|WmiObject)|Rename-(Computer|Item|ItemProperty)|Reset-ComputerMachinePassword|Resolve-Path|Restart-(Computer|Service)|Restore-Computer|Resume-(Job|Service)|Save-Help|Select-(Object|String|Xml)|Send-MailMessage|Set-(Alias|Content|Date|Item|ItemProperty|Location|PSBreakpoint|PSDebug|PSSessionConfiguration|Service|StrictMode|TraceSource|Variable|WmiInstance)|Show-(Command|ControlPanelItem|EventLog)|Sort-Object|Split-Path|Start-(Job|Process|Service|Sleep|Transaction)|Stop-(Computer|Job|Process|Service)|Suspend-(Job|Service)|Tee-Object|Test-(ComputerSecureChannel|Connection|ModuleManifest|Path|PSSessionConfigurationFile)|Trace-Command|Unblock-File|Undo-Transaction|Unregister-(Event|PSSessionConfiguration)|Update-(FormatData|Help|List|TypeData)|Use-Transaction|Wait-(Event|Job|Process)|Where-Object|Write-(Debug|Error|EventLog|Host|Output|Progress|Verbose|Warning))\b/i,/\b(ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(\W?)(!|-(eq|ne|gt|ge|lt|le|sh[lr]|not|b?(and|x?or)|(Not)?(Like|Match|Contains|In)|Replace|Join|is(Not)?|as)\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/},Prism.languages.powershell.string[0].inside["boolean"]=Prism.languages.powershell["boolean"],Prism.languages.powershell.string[0].inside.variable=Prism.languages.powershell.variable,Prism.languages.powershell.string[0].inside["function"].inside=Prism.util.clone(Prism.languages.powershell),Prism.languages.processing=Prism.languages.extend("clike",{keyword:/\b(?:break|catch|case|class|continue|default|else|extends|final|for|if|implements|import|new|null|private|public|return|static|super|switch|this|try|void|while)\b/,operator:/<[<=]?|>[>=]?|&&?|\|\|?|[%?]|[!=+\-*\/]=?/}),Prism.languages.insertBefore("processing","number",{constant:/\b(?!XML\b)[A-Z][A-Z\d_]+\b/,type:{pattern:/\b(?:boolean|byte|char|color|double|float|int|XML|[A-Z][A-Za-z\d_]*)\b/,alias:"variable"}}),Prism.languages.processing["function"].pattern=/[a-z0-9_]+(?=\s*\()/i,Prism.languages.processing["class-name"].alias="variable",Prism.languages.prolog={comment:[/%.+/,/\/\*[\s\S]*?\*\//],string:/(["'])(?:\1\1|\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,builtin:/\b(?:fx|fy|xf[xy]?|yfx?)\b/,variable:/\b[A-Z_]\w*/,"function":/\b[a-z]\w*(?:(?=\()|\/\d+)/,number:/\b\d+\.?\d*/,operator:/[:\\=><\-?*@\/;+^|!$.]+|\b(?:is|mod|not|xor)\b/,punctuation:/[(){}\[\],]/},Prism.languages.properties={comment:/^[ \t]*[#!].*$/m,"attr-value":{pattern:/(^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+?(?: *[=:] *| ))(?:\\(?:\r\n|[\s\S])|.)+/m,lookbehind:!0},"attr-name":/^[ \t]*(?:\\(?:\r\n|[\s\S])|[^\\\s:=])+?(?= *[ =:]| )/m,punctuation:/[=:]/},Prism.languages.protobuf=Prism.languages.extend("clike",{keyword:/\b(package|import|message|enum)\b/,builtin:/\b(required|repeated|optional|reserved)\b/,primitive:{pattern:/\b(double|float|int32|int64|uint32|uint64|sint32|sint64|fixed32|fixed64|sfixed32|sfixed64|bool|string|bytes)\b/,alias:"symbol"}}),function(e){e.languages.puppet={heredoc:[{pattern:/(@\("([^"\r\n\/):]+)"(?:\/[nrts$uL]*)?\).*(?:\r?\n|\r))(?:.*(?:\r?\n|\r))*?[ \t]*\|?[ \t]*-?[ \t]*\2/,lookbehind:!0,alias:"string",inside:{punctuation:/(?=\S).*\S(?= *$)/}},{pattern:/(@\(([^"\r\n\/):]+)(?:\/[nrts$uL]*)?\).*(?:\r?\n|\r))(?:.*(?:\r?\n|\r))*?[ \t]*\|?[ \t]*-?[ \t]*\2/,lookbehind:!0,alias:"string",inside:{punctuation:/(?=\S).*\S(?= *$)/}},{pattern:/@\("?(?:[^"\r\n\/):]+)"?(?:\/[nrts$uL]*)?\)/,alias:"string",inside:{punctuation:{pattern:/(\().+?(?=\))/,lookbehind:!0}}}],"multiline-comment":{pattern:/(^|[^\\])\/\*[\s\S]*?\*\//,lookbehind:!0,alias:"comment"},regex:{pattern:/((?:\bnode\s+|[~=\(\[\{,]\s*|[=+]>\s*|^\s*))\/(?:[^\/\\]|\\[\s\S])+\/(?:[imx]+\b|\B)/,lookbehind:!0,inside:{"extended-regex":{pattern:/^\/(?:[^\/\\]|\\[\s\S])+\/[im]*x[im]*$/,inside:{comment:/#.*/}}}},comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},string:{pattern:/(["'])(?:\$\{(?:[^'"}]|(["'])(?:(?!\2)[^\\]|\\[\s\S])*\2)+\}|(?!\1)[^\\]|\\[\s\S])*\1/,inside:{"double-quoted":{pattern:/^"[\s\S]*"$/,inside:{}}}},variable:{pattern:/\$(?:::)?\w+(?:::\w+)*/,inside:{punctuation:/::/}},"attr-name":/(?:\w+|\*)(?=\s*=>)/,"function":[{pattern:/(\.)(?!\d)\w+/,lookbehind:!0},/\b(?:contain|debug|err|fail|include|info|notice|realize|require|tag|warning)\b|\b(?!\d)\w+(?=\()/],number:/\b(?:0x[a-f\d]+|\d+(?:\.\d+)?(?:e-?\d+)?)\b/i,"boolean":/\b(?:true|false)\b/,keyword:/\b(?:application|attr|case|class|consumes|default|define|else|elsif|function|if|import|inherits|node|private|produces|type|undef|unless)\b/,datatype:{pattern:/\b(?:Any|Array|Boolean|Callable|Catalogentry|Class|Collection|Data|Default|Enum|Float|Hash|Integer|NotUndef|Numeric|Optional|Pattern|Regexp|Resource|Runtime|Scalar|String|Struct|Tuple|Type|Undef|Variant)\b/,alias:"symbol"},operator:/=[=~>]?|![=~]?|<(?:<\|?|[=~|-])?|>[>=]?|->?|~>|\|>?>?|[*\/%+?]|\b(?:and|in|or)\b/,punctuation:/[\[\]{}().,;]|:+/};var t=[{pattern:/(^|[^\\])\$\{(?:[^'"{}]|\{[^}]*\}|(["'])(?:(?!\2)[^\\]|\\[\s\S])*\2)+\}/,lookbehind:!0,inside:{"short-variable":{pattern:/(^\$\{)(?!\w+\()(?:::)?\w+(?:::\w+)*/,lookbehind:!0,alias:"variable",inside:{punctuation:/::/}},delimiter:{pattern:/^\$/,alias:"variable"},rest:e.util.clone(e.languages.puppet)}},{pattern:/(^|[^\\])\$(?:::)?\w+(?:::\w+)*/,lookbehind:!0,alias:"variable",inside:{punctuation:/::/}}];e.languages.puppet.heredoc[0].inside.interpolation=t,e.languages.puppet.string.inside["double-quoted"].inside.interpolation=t}(Prism),function(a){a.languages.pure={"inline-lang":{pattern:/%<[\s\S]+?%>/,inside:{lang:{pattern:/(^%< *)-\*-.+?-\*-/,lookbehind:!0,alias:"comment"},delimiter:{pattern:/^%<.*|%>$/,alias:"punctuation"}}},comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0},/#!.+/],string:/"(?:\\.|[^"\\\r\n])*"/,number:{pattern:/((?:\.\.)?)(?:\b(?:inf|nan)\b|\b0x[\da-f]+|(?:\b(?:0b)?\d+(?:\.\d)?|\B\.\d)\d*(?:e[+-]?\d+)?L?)/i,lookbehind:!0},keyword:/\b(?:ans|break|bt|case|catch|cd|clear|const|def|del|dump|else|end|exit|extern|false|force|help|if|infix[lr]?|interface|let|ls|mem|namespace|nonfix|NULL|of|otherwise|outfix|override|postfix|prefix|private|public|pwd|quit|run|save|show|stats|then|throw|trace|true|type|underride|using|when|with)\b/,"function":/\b(?:abs|add_(?:(?:fundef|interface|macdef|typedef)(?:_at)?|addr|constdef|vardef)|all|any|applp?|arity|bigintp?|blob(?:_crc|_size|p)?|boolp?|byte_(?:matrix|pointer)|byte_c?string(?:_pointer)?|calloc|cat|catmap|ceil|char[ps]?|check_ptrtag|chr|clear_sentry|clearsym|closurep?|cmatrixp?|cols?|colcat(?:map)?|colmap|colrev|colvector(?:p|seq)?|complex(?:_float_(?:matrix|pointer)|_matrix(?:_view)?|_pointer|p)?|conj|cookedp?|cst|cstring(?:_(?:dup|list|vector))?|curry3?|cyclen?|del_(?:constdef|fundef|interface|macdef|typedef|vardef)|delete|diag(?:mat)?|dim|dmatrixp?|do|double(?:_matrix(?:_view)?|_pointer|p)?|dowith3?|drop|dropwhile|eval(?:cmd)?|exactp|filter|fix|fixity|flip|float(?:_matrix|_pointer)|floor|fold[lr]1?|frac|free|funp?|functionp?|gcd|get(?:_(?:byte|constdef|double|float|fundef|int(?:64)?|interface(?:_typedef)?|long|macdef|pointer|ptrtag|short|sentry|string|typedef|vardef))?|globsym|hash|head|id|im|imatrixp?|index|inexactp|infp|init|insert|int(?:_matrix(?:_view)?|_pointer|p)?|int64_(?:matrix|pointer)|integerp?|iteraten?|iterwhile|join|keys?|lambdap?|last(?:err(?:pos)?)?|lcd|list[2p]?|listmap|make_ptrtag|malloc|map|matcat|matrixp?|max|member|min|nanp|nargs|nmatrixp?|null|numberp?|ord|pack(?:ed)?|pointer(?:_cast|_tag|_type|p)?|pow|pred|ptrtag|put(?:_(?:byte|double|float|int(?:64)?|long|pointer|short|string))?|rationalp?|re|realp?|realloc|recordp?|redim|reduce(?:_with)?|refp?|repeatn?|reverse|rlistp?|round|rows?|rowcat(?:map)?|rowmap|rowrev|rowvector(?:p|seq)?|same|scan[lr]1?|sentry|sgn|short_(?:matrix|pointer)|slice|smatrixp?|sort|split|str|strcat|stream|stride|string(?:_(?:dup|list|vector)|p)?|subdiag(?:mat)?|submat|subseq2?|substr|succ|supdiag(?:mat)?|symbolp?|tail|take|takewhile|thunkp?|transpose|trunc|tuplep?|typep|ubyte|uint(?:64)?|ulong|uncurry3?|unref|unzip3?|update|ushort|vals?|varp?|vector(?:p|seq)?|void|zip3?|zipwith3?)\b/,special:{pattern:/\b__[a-z]+__\b/i,alias:"builtin"},operator:/(?=\b_|[^_])[!"#$%&'*+,\-.\/:<=>?@\\^_`|~\u00a1-\u00bf\u00d7-\u00f7\u20d0-\u2bff]+|\b(?:and|div|mod|not|or)\b/,punctuation:/[(){}\[\];,|]/};var i="%< *-\\*- *{lang}\\d* *-\\*-[\\s\\S]+?%>";["c",{lang:"c++",alias:"cpp"},"fortran","ats","dsp"].forEach(function(e){var t=e;if("string"!=typeof e&&(t=e.alias,e=e.lang),a.languages[t]){var n={};n["inline-lang-"+t]={pattern:RegExp(i.replace("{lang}",e.replace(/([.+*?\/\\(){}\[\]])/g,"\\$1")),"i"),inside:a.util.clone(a.languages.pure["inline-lang"].inside)},n["inline-lang-"+t].inside.rest=a.util.clone(a.languages[t]),a.languages.insertBefore("pure","inline-lang",n)}}),a.languages.c&&(a.languages.pure["inline-lang"].inside.rest=a.util.clone(a.languages.c))}(Prism),Prism.languages.python={"triple-quoted-string":{pattern:/"""[\s\S]+?"""|'''[\s\S]+?'''/,alias:"string"},comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},string:{pattern:/("|')(?:\\\\|\\?[^\\\r\n])*?\1/,greedy:!0},"function":{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_][a-zA-Z0-9_]*(?=\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)[a-z0-9_]+/i,lookbehind:!0},keyword:/\b(?:as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/,"boolean":/\b(?:True|False)\b/,number:/\b-?(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,operator:/[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/,punctuation:/[{}[\];(),.:]/},Prism.languages.q={string:/"(?:\\.|[^"\\\r\n])*"/,comment:[{pattern:/([\t )\]}])\/.*/,lookbehind:!0},{pattern:/(^|\r?\n|\r)\/[\t ]*(?:(?:\r?\n|\r)(?:.*(?:\r?\n|\r))*?(?:\\(?=[\t ]*(?:\r?\n|\r))|$)|\S.*)/,lookbehind:!0},/^\\[\t ]*(?:\r?\n|\r)[\s\S]+/m,/^#!.+/m],symbol:/`(?::\S+|[\w.]*)/,datetime:{pattern:/0N[mdzuvt]|0W[dtz]|\d{4}\.\d\d(?:m|\.\d\d(?:T(?:\d\d(?::\d\d(?::\d\d(?:[.:]\d\d\d)?)?)?)?)?[dz]?)|\d\d:\d\d(?::\d\d(?:[.:]\d\d\d)?)?[uvt]?/,alias:"number"},number:/\b-?(?![01]:)(?:0[wn]|0W[hj]?|0N[hje]?|0x[\da-fA-F]+|\d+\.?\d*(?:e[+-]?\d+)?[hjfeb]?)/,keyword:/\\\w+\b|\b(?:abs|acos|aj0?|all|and|any|asc|asin|asof|atan|attr|avgs?|binr?|by|ceiling|cols|cor|cos|count|cov|cross|csv|cut|delete|deltas|desc|dev|differ|distinct|div|do|dsave|ej|enlist|eval|except|exec|exit|exp|fby|fills|first|fkeys|flip|floor|from|get|getenv|group|gtime|hclose|hcount|hdel|hopen|hsym|iasc|identity|idesc|if|ij|in|insert|inter|inv|keys?|last|like|list|ljf?|load|log|lower|lsq|ltime|ltrim|mavg|maxs?|mcount|md5|mdev|med|meta|mins?|mmax|mmin|mmu|mod|msum|neg|next|not|null|or|over|parse|peach|pj|plist|prds?|prev|prior|rand|rank|ratios|raze|read0|read1|reciprocal|reval|reverse|rload|rotate|rsave|rtrim|save|scan|scov|sdev|select|set|setenv|show|signum|sin|sqrt|ssr?|string|sublist|sums?|sv|svar|system|tables|tan|til|trim|txf|type|uj|ungroup|union|update|upper|upsert|value|var|views?|vs|wavg|where|while|within|wj1?|wsum|ww|xasc|xbar|xcols?|xdesc|xexp|xgroup|xkey|xlog|xprev|xrank)\b/,adverb:{pattern:/['\/\\]:?|\beach\b/,alias:"function"},verb:{pattern:/(?:\B\.\B|\b[01]:|<[=>]?|>=?|[:+\-*%,!?_~=|$&#@^]):?/,alias:"operator"},punctuation:/[(){}\[\];.]/},Prism.languages.qore=Prism.languages.extend("clike",{comment:{pattern:/(^|[^\\])(?:\/\*[\w\W]*?\*\/|(?:\/\/|#).*)/,lookbehind:!0},string:/("|')(\\(?:\r\n|[\s\S])|(?!\1)[^\\])*\1/,variable:/\$(?!\d)\w+\b/,keyword:/\b(?:abstract|any|assert|binary|bool|boolean|break|byte|case|catch|char|class|code|const|continue|data|default|do|double|else|enum|extends|final|finally|float|for|goto|hash|if|implements|import|inherits|instanceof|int|interface|long|my|native|new|nothing|null|object|our|own|private|reference|rethrow|return|short|soft(?:int|float|number|bool|string|date|list)|static|strictfp|string|sub|super|switch|synchronized|this|throw|throws|transient|try|void|volatile|while)\b/,number:/\b(?:0b[01]+|0x[\da-f]*\.?[\da-fp\-]+|\d*\.?\d+e?\d*[df]|\d*\.?\d+)\b/i,"boolean":/\b(?:true|false)\b/i,operator:{pattern:/(^|[^\.])(?:\+[+=]?|-[-=]?|[!=](?:==?|~)?|>>?=?|<(?:=>?|<=?)?|&[&=]?|\|[|=]?|[*\/%^]=?|[~?])/,lookbehind:!0},"function":/\$?\b(?!\d)\w+(?=\()/}),Prism.languages.r={comment:/#.*/,string:/(['"])(?:\\?.)*?\1/,"percent-operator":{pattern:/%[^%\s]*%/,alias:"operator"},"boolean":/\b(?:TRUE|FALSE)\b/,ellipsis:/\.\.(?:\.|\d+)/,number:[/\b(?:NaN|Inf)\b/,/\b(?:0x[\dA-Fa-f]+(?:\.\d*)?|\d*\.?\d+)(?:[EePp][+-]?\d+)?[iL]?\b/],keyword:/\b(?:if|else|repeat|while|function|for|in|next|break|NULL|NA|NA_integer_|NA_real_|NA_complex_|NA_character_)\b/,operator:/->?>?|<(?:=|=!]=?|::?|&&?|\|\|?|[+*\/^$@~]/,punctuation:/[(){}\[\],;]/},function(e){var t=e.util.clone(e.languages.javascript);e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=/<\/?[\w\.:-]+\s*(?:\s+[\w\.:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+|(\{[\w\W]*?\})))?\s*)*\/?>/i,e.languages.jsx.tag.inside["attr-value"].pattern=/=[^\{](?:('|")[\w\W]*?(\1)|[^\s>]+)/i;var n=e.util.clone(e.languages.jsx);delete n.punctuation,n=e.languages.insertBefore("jsx","operator",{punctuation:/=(?={)|[{}[\];(),.:]/},{jsx:n}),e.languages.insertBefore("inside","attr-value",{script:{pattern:/=(\{(?:\{[^}]*\}|[^}])+\})/i,inside:n,alias:"language-javascript"}},e.languages.jsx.tag)}(Prism),Prism.languages.rest={table:[{pattern:/(\s*)(?:\+[=-]+)+\+(?:\r?\n|\r)(?:\1(?:[+|].+)+[+|](?:\r?\n|\r))+\1(?:\+[=-]+)+\+/,lookbehind:!0,inside:{punctuation:/\||(?:\+[=-]+)+\+/}},{pattern:/(\s*)(?:=+ +)+=+((?:\r?\n|\r)\1.+)+(?:\r?\n|\r)\1(?:=+ +)+=+(?=(?:\r?\n|\r){2}|\s*$)/,lookbehind:!0,inside:{punctuation:/[=-]+/}}],"substitution-def":{pattern:/(^\s*\.\. )\|(?:[^|\s](?:[^|]*[^|\s])?)\| [^:]+::/m,lookbehind:!0,inside:{substitution:{pattern:/^\|(?:[^|\s]|[^|\s][^|]*[^|\s])\|/,alias:"attr-value",inside:{punctuation:/^\||\|$/}},directive:{pattern:/( +)[^:]+::/,lookbehind:!0,alias:"function",inside:{punctuation:/::$/}}}},"link-target":[{pattern:/(^\s*\.\. )\[[^\]]+\]/m,lookbehind:!0,alias:"string",inside:{punctuation:/^\[|\]$/}},{pattern:/(^\s*\.\. )_(?:`[^`]+`|(?:[^:\\]|\\.)+):/m,lookbehind:!0,alias:"string",inside:{punctuation:/^_|:$/}}],directive:{pattern:/(^\s*\.\. )[^:]+::/m,lookbehind:!0,alias:"function",inside:{punctuation:/::$/}},comment:{pattern:/(^\s*\.\.)(?:(?: .+)?(?:(?:\r?\n|\r).+)+| .+)(?=(?:\r?\n|\r){2}|$)/m,lookbehind:!0},title:[{pattern:/^(([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2+)(?:\r?\n|\r).+(?:\r?\n|\r)\1$/m,inside:{punctuation:/^[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+|[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+$/,important:/.+/}},{pattern:/(^|(?:\r?\n|\r){2}).+(?:\r?\n|\r)([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2+(?=\r?\n|\r|$)/,lookbehind:!0,inside:{punctuation:/[!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]+$/,important:/.+/}}],hr:{pattern:/((?:\r?\n|\r){2})([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\2{3,}(?=(?:\r?\n|\r){2})/,lookbehind:!0,alias:"punctuation"},field:{pattern:/(^\s*):[^:\r\n]+:(?= )/m,lookbehind:!0,alias:"attr-name"},"command-line-option":{pattern:/(^\s*)(?:[+-][a-z\d]|(?:\-\-|\/)[a-z\d-]+)(?:[ =](?:[a-z][a-z\d_-]*|<[^<>]+>))?(?:, (?:[+-][a-z\d]|(?:\-\-|\/)[a-z\d-]+)(?:[ =](?:[a-z][a-z\d_-]*|<[^<>]+>))?)*(?=(?:\r?\n|\r)? {2,}\S)/im,lookbehind:!0,alias:"symbol"},"literal-block":{pattern:/::(?:\r?\n|\r){2}([ \t]+).+(?:(?:\r?\n|\r)\1.+)*/,inside:{"literal-block-punctuation":{pattern:/^::/,alias:"punctuation"}}},"quoted-literal-block":{pattern:/::(?:\r?\n|\r){2}([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]).*(?:(?:\r?\n|\r)\1.*)*/,inside:{"literal-block-punctuation":{pattern:/^(?:::|([!"#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~])\1*)/m,alias:"punctuation"}}},"list-bullet":{pattern:/(^\s*)(?:[*+\-\u2022\u2023\u2043]|\(?(?:\d+|[a-z]|[ivxdclm]+)\)|(?:\d+|[a-z]|[ivxdclm]+)\.)(?= )/im,lookbehind:!0,alias:"punctuation"},"doctest-block":{pattern:/(^\s*)>>> .+(?:(?:\r?\n|\r).+)*/m,lookbehind:!0,inside:{punctuation:/^>>>/}},inline:[{pattern:/(^|[\s\-:\/'"<(\[{])(?::[^:]+:`.*?`|`.*?`:[^:]+:|(\*\*?|``?|\|)(?!\s).*?[^\s]\2(?=[\s\-.,:;!?\\\/'")\]}]|$))/m,lookbehind:!0,inside:{bold:{pattern:/(^\*\*).+(?=\*\*$)/,lookbehind:!0},italic:{pattern:/(^\*).+(?=\*$)/,lookbehind:!0},"inline-literal":{pattern:/(^``).+(?=``$)/,lookbehind:!0,alias:"symbol"},role:{pattern:/^:[^:]+:|:[^:]+:$/,alias:"function",inside:{punctuation:/^:|:$/}},"interpreted-text":{pattern:/(^`).+(?=`$)/,lookbehind:!0,alias:"attr-value"},substitution:{pattern:/(^\|).+(?=\|$)/,lookbehind:!0,alias:"attr-value"},punctuation:/\*\*?|``?|\|/}}],link:[{pattern:/\[[^\]]+\]_(?=[\s\-.,:;!?\\\/'")\]}]|$)/,alias:"string",inside:{punctuation:/^\[|\]_$/}},{pattern:/(?:\b[a-z\d](?:[_.:+]?[a-z\d]+)*_?_|`[^`]+`_?_|_`[^`]+`)(?=[\s\-.,:;!?\\\/'")\]}]|$)/i,alias:"string",inside:{punctuation:/^_?`|`$|`?_?_$/}}],punctuation:{pattern:/(^\s*)(?:\|(?= |$)|(?:---?|\u2014|\.\.|__)(?= )|\.\.$)/m,lookbehind:!0}},Prism.languages.rip={comment:/#.*/,keyword:/(?:=>|->)|\b(?:class|if|else|switch|case|return|exit|try|catch|finally|raise)\b/,builtin:/@|\bSystem\b/,"boolean":/\b(?:true|false)\b/,date:/\b\d{4}-\d{2}-\d{2}\b/,time:/\b\d{2}:\d{2}:\d{2}\b/,datetime:/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\b/,character:/\B`[^\s`'",.:;#\/\\()<>\[\]{}]\b/,regex:{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/(?=\s*($|[\r\n,.;})]))/,lookbehind:!0},symbol:/:[^\d\s`'",.:;#\/\\()<>\[\]{}][^\s`'",.:;#\/\\()<>\[\]{}]*/,string:/("|')(\\?.)*?\1/,number:/[+-]?(?:(?:\d+\.\d+)|(?:\d+))/,punctuation:/(?:\.{2,3})|[`,.:;=\/\\()<>\[\]{}]/,reference:/[^\d\s`'",.:;#\/\\()<>\[\]{}][^\s`'",.:;#\/\\()<>\[\]{}]*/},Prism.languages.roboconf={comment:/#.*/,keyword:{pattern:/(^|\s)(?:(?:facet|instance of)(?=[ \t]+[\w-]+[ \t]*\{)|(?:external|import)\b)/,lookbehind:!0},component:{pattern:/[\w-]+(?=[ \t]*\{)/,alias:"variable"},property:/[\w.-]+(?=[ \t]*:)/,value:{pattern:/(=[ \t]*)[^,;]+/,lookbehind:!0,alias:"attr-value"},optional:{pattern:/\(optional\)/,alias:"builtin"},wildcard:{pattern:/(\.)\*/,lookbehind:!0,alias:"operator"},punctuation:/[{},.;:=]/},function(e){e.languages.crystal=e.languages.extend("ruby",{keyword:[/\b(?:abstract|alias|as|asm|begin|break|case|class|def|do|else|elsif|end|ensure|enum|extend|for|fun|if|ifdef|include|instance_sizeof|lib|macro|module|next|of|out|pointerof|private|protected|rescue|return|require|self|sizeof|struct|super|then|type|typeof|union|unless|until|when|while|with|yield|__DIR__|__FILE__|__LINE__)\b/,{pattern:/(\.\s*)(?:is_a|responds_to)\?/,lookbehind:!0}],number:/\b(?:0b[01_]*[01]|0o[0-7_]*[0-7]|0x[0-9a-fA-F_]*[0-9a-fA-F]|(?:[0-9](?:[0-9_]*[0-9])?)(?:\.[0-9_]*[0-9])?(?:[eE][+-]?[0-9_]*[0-9])?)(?:_(?:[uif](?:8|16|32|64))?)?\b/});var t=e.util.clone(e.languages.crystal);e.languages.insertBefore("crystal","string",{attribute:{pattern:/@\[.+?\]/,alias:"attr-name",inside:{delimiter:{pattern:/^@\[|\]$/,alias:"tag"},rest:t}},expansion:[{pattern:/\{\{.+?\}\}/,inside:{delimiter:{pattern:/^\{\{|\}\}$/,alias:"tag"},rest:t}},{pattern:/\{%.+?%\}/,inside:{delimiter:{pattern:/^\{%|%\}$/,alias:"tag"},rest:t}}]})}(Prism),Prism.languages.rust={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:[/b?r(#*)"(?:\\?.)*?"\1/,/b?("|')(?:\\?.)*?\1/],keyword:/\b(?:abstract|alignof|as|be|box|break|const|continue|crate|do|else|enum|extern|false|final|fn|for|if|impl|in|let|loop|match|mod|move|mut|offsetof|once|override|priv|pub|pure|ref|return|sizeof|static|self|struct|super|true|trait|type|typeof|unsafe|unsized|use|virtual|where|while|yield)\b/,attribute:{pattern:/#!?\[.+?\]/,alias:"attr-name"},"function":[/[a-z0-9_]+(?=\s*\()/i,/[a-z0-9_]+!(?=\s*\(|\[)/i],"macro-rules":{pattern:/[a-z0-9_]+!/i,alias:"function"},number:/\b-?(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(\d(_?\d)*)?\.?\d(_?\d)*([Ee][+-]?\d+)?)(?:_?(?:[iu](?:8|16|32|64)?|f32|f64))?\b/,"closure-params":{pattern:/\|[^|]*\|(?=\s*[{-])/,inside:{punctuation:/[\|:,]/,operator:/[&*]/}},punctuation:/[{}[\];(),:]|\.+|->/,operator:/[-+*\/%!^=]=?|@|&[&=]?|\|[|=]?|<>?=?/},Prism.languages.sas={datalines:{pattern:/^\s*(?:(?:data)?lines|cards);[\s\S]+?(?:\r?\n|\r);/im,alias:"string",inside:{keyword:{pattern:/^(\s*)(?:(?:data)?lines|cards)/i,lookbehind:!0},punctuation:/;/}},comment:[{pattern:/(^\s*|;\s*)\*.*;/m,lookbehind:!0},/\/\*[\s\S]+?\*\//],datetime:{pattern:/'[^']+'(?:dt?|t)\b/i,alias:"number"},string:/(["'])(?:\1\1|(?!\1)[\s\S])*\1/,keyword:/\b(?:data|else|format|if|input|proc\s\w+|quit|run|then)\b/i,number:/(?:\B-|\b)(?:[\da-f]+x|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,operator:/\*\*?|\|\|?|!!?|\xa6\xa6?|<[>=]?|>[<=]?|[-+\/=&]|[~\xac^]=?|\b(?:eq|ne|gt|lt|ge|le|in|not)\b/i,punctuation:/[$%@.(){}\[\];,\\]/},function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t]+.+)*/m,lookbehind:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,inside:{atrule:/(?:@[\w-]+|[+=])/m}}}),delete e.languages.sass.atrule;var t=/((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|or|not)\b/,{pattern:/(\s+)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s]+.*)/m,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,delete e.languages.sass.selector,e.languages.insertBefore("sass","punctuation",{selector:{ +pattern:/([ \t]*)\S(?:,?[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,?[^,\r\n]+)*)*/,lookbehind:!0}})}(Prism),Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\w\W]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-]+(?:\([^()]+\)|[^(])*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)*url(?=\()/i,selector:{pattern:/(?=\S)[^@;\{\}\(\)]?([^@;\{\}\(\)]|&|#\{\$[-_\w]+\})+(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/m,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-_\w]+/,variable:/\$[-_\w]+|#\{\$[-_\w]+\}/}}}),Prism.languages.insertBefore("scss","atrule",{keyword:[/@(?:if|else(?: if)?|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)/i,{pattern:/( +)(?:from|through)(?= )/,lookbehind:!0}]}),Prism.languages.scss.property={pattern:/(?:[\w-]|\$[-_\w]+|#\{\$[-_\w]+\})+(?=\s*:)/i,inside:{variable:/\$[-_\w]+|#\{\$[-_\w]+\}/}},Prism.languages.insertBefore("scss","important",{variable:/\$[-_\w]+|#\{\$[-_\w]+\}/}),Prism.languages.insertBefore("scss","function",{placeholder:{pattern:/%[-_\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},"boolean":/\b(?:true|false)\b/,"null":/\bnull\b/,operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|or|not)(?=\s)/,lookbehind:!0}}),Prism.languages.scss.atrule.inside.rest=Prism.util.clone(Prism.languages.scss),Prism.languages.scala=Prism.languages.extend("java",{keyword:/<-|=>|\b(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|null|object|override|package|private|protected|return|sealed|self|super|this|throw|trait|try|type|val|var|while|with|yield)\b/,string:[{pattern:/"""[\W\w]*?"""/,greedy:!0},{pattern:/("|')(?:\\\\|\\?[^\\\r\n])*?\1/,greedy:!0}],builtin:/\b(?:String|Int|Long|Short|Byte|Boolean|Double|Float|Char|Any|AnyRef|AnyVal|Unit|Nothing)\b/,number:/\b(?:0x[\da-f]*\.?[\da-f]+|\d*\.?\d+e?\d*[dfl]?)\b/i,symbol:/'[^\d\s\\]\w*/}),delete Prism.languages.scala["class-name"],delete Prism.languages.scala["function"],Prism.languages.scheme={comment:/;.*/,string:/"(?:[^"\\\r\n]|\\.)*?"|'[^('\s]*/,keyword:{pattern:/(\()(?:define(?:-syntax|-library|-values)?|(?:case-)?lambda|let(?:\*|rec)?(?:-values)?|else|if|cond|begin|delay(?:-force)?|parameterize|guard|set!|(?:quasi-)?quote|syntax-rules)/,lookbehind:!0},builtin:{pattern:/(\()(?:(?:cons|car|cdr|list|call-with-current-continuation|call\/cc|append|abs|apply|eval)\b|null\?|pair\?|boolean\?|eof-object\?|char\?|procedure\?|number\?|port\?|string\?|vector\?|symbol\?|bytevector\?)/,lookbehind:!0},number:{pattern:/(\s|\))[-+]?[0-9]*\.?[0-9]+(?:\s*[-+]\s*[0-9]*\.?[0-9]+i)?\b/,lookbehind:!0},"boolean":/#[tf]/,operator:{pattern:/(\()(?:[-+*%\/]|[<>]=?|=>?)/,lookbehind:!0},"function":{pattern:/(\()[^\s()]*(?=\s)/,lookbehind:!0},punctuation:/[()]/},Prism.languages.smalltalk={comment:/"(?:""|[^"])+"/,string:/'(?:''|[^'])+'/,symbol:/#[\da-z]+|#(?:-|([+\/\\*~<>=@%|&?!])\1?)|#(?=\()/i,"block-arguments":{pattern:/(\[\s*):[^\[|]*?\|/,lookbehind:!0,inside:{variable:/:[\da-z]+/i,punctuation:/\|/}},"temporary-variables":{pattern:/\|[^|]+\|/,inside:{variable:/[\da-z]+/i,punctuation:/\|/}},keyword:/\b(?:nil|true|false|self|super|new)\b/,character:{pattern:/\$./,alias:"string"},number:[/\d+r-?[\dA-Z]+(?:\.[\dA-Z]+)?(?:e-?\d+)?/,/(?:\B-|\b)\d+(?:\.\d+)?(?:e-?\d+)?/],operator:/[<=]=?|:=|~[~=]|\/\/?|\\\\|>[>=]?|[!^+\-*&|,@]/,punctuation:/[.;:?\[\](){}]/},function(a){var e=/\{\*[\w\W]+?\*\}|\{[\w\W]+?\}/g,n="{literal}",i="{/literal}",r=!1;a.languages.smarty=a.languages.extend("markup",{smarty:{pattern:e,inside:{delimiter:{pattern:/^\{|\}$/i,alias:"punctuation"},string:/(["'])(?:\\?.)*?\1/,number:/\b-?(?:0x[\dA-Fa-f]+|\d*\.?\d+(?:[Ee][-+]?\d+)?)\b/,variable:[/\$(?!\d)\w+/,/#(?!\d)\w+#/,{pattern:/(\.|->)(?!\d)\w+/,lookbehind:!0},{pattern:/(\[)(?!\d)\w+(?=\])/,lookbehind:!0}],"function":[{pattern:/(\|\s*)@?(?!\d)\w+/,lookbehind:!0},/^\/?(?!\d)\w+/,/(?!\d)\w+(?=\()/],"attr-name":{pattern:/\w+\s*=\s*(?:(?!\d)\w+)?/,inside:{variable:{pattern:/(=\s*)(?!\d)\w+/,lookbehind:!0},operator:/=/}},punctuation:[/[\[\]().,:`]|\->/],operator:[/[+\-*\/%]|==?=?|[!<>]=?|&&|\|\|?/,/\bis\s+(?:not\s+)?(?:div|even|odd)(?:\s+by)?\b/,/\b(?:eq|neq?|gt|lt|gt?e|lt?e|not|mod|or|and)\b/],keyword:/\b(?:false|off|on|no|true|yes)\b/}}}),a.languages.insertBefore("smarty","tag",{"smarty-comment":{pattern:/\{\*[\w\W]*?\*\}/,alias:["smarty","comment"]}}),a.hooks.add("before-highlight",function(t){"smarty"===t.language&&(t.tokenStack=[],t.code=t.code.replace(e,function(e){return e===i&&(r=!1),r?e:(e===n&&(r=!0),t.tokenStack.push(e),"___SMARTY"+t.tokenStack.length+"___")}))}),a.hooks.add("after-highlight",function(e){if("smarty"===e.language){for(var t,n=0;t=e.tokenStack[n];n++)e.highlightedCode=e.highlightedCode.replace("___SMARTY"+(n+1)+"___",a.highlight(t,e.grammar,"smarty").replace(/\$/g,"$$$$"));e.element.innerHTML=e.highlightedCode}})}(Prism),Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\w\W]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},string:{pattern:/(^|[^@\\])("|')(?:\\?[\s\S])*?\2/,lookbehind:!0},variable:/@[\w.$]+|@("|'|`)(?:\\?[\s\S])+?\1/,"function":/\b(?:COUNT|SUM|AVG|MIN|MAX|FIRST|LAST|UCASE|LCASE|MID|LEN|ROUND|NOW|FORMAT)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR VARYING|CHARACTER (?:SET|VARYING)|CHARSET|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMN|COLUMNS|COMMENT|COMMIT|COMMITTED|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|DATA(?:BASES?)?|DATE(?:TIME)?|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITER(?:S)?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE(?: PRECISION)?|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE KEY|ELSE|ENABLE|ENCLOSED BY|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPE(?:D BY)?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|IDENTITY(?:_INSERT|COL)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTO|INVOKER|ISOLATION LEVEL|JOIN|KEYS?|KILL|LANGUAGE SQL|LAST|LEFT|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MODIFIES SQL DATA|MODIFY|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL(?: CHAR VARYING| CHARACTER(?: VARYING)?| VARCHAR)?|NATURAL|NCHAR(?: VARCHAR)?|NEXT|NO(?: SQL|CHECK|CYCLE)?|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READ(?:S SQL DATA|TEXT)?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEATABLE|REPLICATION|REQUIRE|RESTORE|RESTRICT|RETURNS?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE MODE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|START(?:ING BY)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED BY|TEXT(?:SIZE)?|THEN|TIMESTAMP|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNPIVOT|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?)\b/i,"boolean":/\b(?:TRUE|FALSE|NULL)\b/i,number:/\b-?(?:0x)?\d*\.?[\da-f]+\b/,operator:/[-+*\/=%^~]|&&?|\|?\||!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|IN|LIKE|NOT|OR|IS|DIV|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t={url:/url\((["']?).*?\1\)/i,string:/("|')(?:[^\\\r\n]|\\(?:\r\n|[\s\S]))*?\1/,interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:if|else|for|return|unless)(?=\s+|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,number:/\b\d+(?:\.\d+)?%?/,"boolean":/\b(?:true|false)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.+|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],punctuation:/[{}()\[\];:,]/};t.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:e.util.clone(t)},t.func={pattern:/[\w-]+\([^)]*\).*/,inside:{"function":/^[^(]+/,rest:e.util.clone(t)}},e.languages.stylus={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*)/,lookbehind:!0},"atrule-declaration":{pattern:/(^\s*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:t}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:(?:\{[^}]*\}|.+)|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:t}},statement:{pattern:/(^[ \t]*)(?:if|else|for|return|unless)[ \t]+.+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:t}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)[^{\r\n]*(?:;|[^{\r\n,](?=$)(?!(\r?\n|\r)(?:\{|\2[ \t]+)))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:t.interpolation}},rest:t}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\))?|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\))?|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t]+)))/m,lookbehind:!0,inside:{interpolation:t.interpolation,punctuation:/[{},]/}},func:t.func,string:t.string,interpolation:t.interpolation,punctuation:/[{}()\[\];:.]/}}(Prism),Prism.languages.swift=Prism.languages.extend("clike",{string:{pattern:/("|')(\\(?:\((?:[^()]|\([^)]+\))+\)|\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0,inside:{interpolation:{pattern:/\\\((?:[^()]|\([^)]+\))+\)/,inside:{delimiter:{pattern:/^\\\(|\)$/,alias:"variable"}}}}},keyword:/\b(as|associativity|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic(?:Type)?|else|enum|extension|fallthrough|final|for|func|get|guard|if|import|in|infix|init|inout|internal|is|lazy|left|let|mutating|new|none|nonmutating|operator|optional|override|postfix|precedence|prefix|private|Protocol|public|repeat|required|rethrows|return|right|safe|self|Self|set|static|struct|subscript|super|switch|throws?|try|Type|typealias|unowned|unsafe|var|weak|where|while|willSet|__(?:COLUMN__|FILE__|FUNCTION__|LINE__))\b/,number:/\b([\d_]+(\.[\de_]+)?|0x[a-f0-9_]+(\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\b/i,constant:/\b(nil|[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\b/,atrule:/@\b(IB(?:Outlet|Designable|Action|Inspectable)|class_protocol|exported|noreturn|NS(?:Copying|Managed)|objc|UIApplicationMain|auto_closure)\b/,builtin:/\b([A-Z]\S+|abs|advance|alignof(?:Value)?|assert|contains|count(?:Elements)?|debugPrint(?:ln)?|distance|drop(?:First|Last)|dump|enumerate|equal|filter|find|first|getVaList|indices|isEmpty|join|last|lexicographicalCompare|map|max(?:Element)?|min(?:Element)?|numericCast|overlaps|partition|print(?:ln)?|reduce|reflect|reverse|sizeof(?:Value)?|sort(?:ed)?|split|startsWith|stride(?:of(?:Value)?)?|suffix|swap|toDebugString|toString|transcode|underestimateCount|unsafeBitCast|with(?:ExtendedLifetime|Unsafe(?:MutablePointers?|Pointers?)|VaList))\b/}),Prism.languages.swift.string.inside.interpolation.inside.rest=Prism.util.clone(Prism.languages.swift),Prism.languages.tcl={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0},string:/"(?:[^"\\\r\n]|\\(?:\r\n|[\s\S]))*"/,variable:[{pattern:/(\$)(?:::)?(?:[a-zA-Z0-9]+::)*[a-zA-Z0-9_]+/,lookbehind:!0},{pattern:/(\$){[^}]+}/,lookbehind:!0},{pattern:/(^\s*set[ \t]+)(?:::)?(?:[a-zA-Z0-9]+::)*[a-zA-Z0-9_]+/m,lookbehind:!0}],"function":{pattern:/(^\s*proc[ \t]+)[^\s]+/m,lookbehind:!0},builtin:[{pattern:/(^\s*)(?:proc|return|class|error|eval|exit|for|foreach|if|switch|while|break|continue)\b/m,lookbehind:!0},/\b(elseif|else)\b/],scope:{pattern:/(^\s*)(global|upvar|variable)\b/m,lookbehind:!0,alias:"constant"},keyword:{pattern:/(^\s*|\[)(after|append|apply|array|auto_(?:execok|import|load|mkindex|qualify|reset)|automkindex_old|bgerror|binary|catch|cd|chan|clock|close|concat|dde|dict|encoding|eof|exec|expr|fblocked|fconfigure|fcopy|file(?:event|name)?|flush|gets|glob|history|http|incr|info|interp|join|lappend|lassign|lindex|linsert|list|llength|load|lrange|lrepeat|lreplace|lreverse|lsearch|lset|lsort|math(?:func|op)|memory|msgcat|namespace|open|package|parray|pid|pkg_mkIndex|platform|puts|pwd|re_syntax|read|refchan|regexp|registry|regsub|rename|Safe_Base|scan|seek|set|socket|source|split|string|subst|Tcl|tcl(?:_endOfWord|_findLibrary|startOf(?:Next|Previous)Word|wordBreak(?:After|Before)|test|vars)|tell|time|tm|trace|unknown|unload|unset|update|uplevel|vwait)\b/m,lookbehind:!0},operator:/!=?|\*\*?|==|&&?|\|\|?|<[=<]?|>[=>]?|[-+~\/%?^]|\b(?:eq|ne|in|ni)\b/,punctuation:/[{}()\[\]]/},function(e){var t="(?:\\([^|)]+\\)|\\[[^\\]]+\\]|\\{[^}]+\\})+",n={css:{pattern:/\{[^}]+\}/,inside:{rest:e.languages.css}},"class-id":{pattern:/(\()[^)]+(?=\))/,lookbehind:!0,alias:"attr-value"},lang:{pattern:/(\[)[^\]]+(?=\])/,lookbehind:!0,alias:"attr-value"},punctuation:/[\\\/]\d+|\S/};e.languages.textile=e.languages.extend("markup",{phrase:{pattern:/(^|\r|\n)\S[\s\S]*?(?=$|\r?\n\r?\n|\r\r)/,lookbehind:!0,inside:{"block-tag":{pattern:RegExp("^[a-z]\\w*(?:"+t+"|[<>=()])*\\."),inside:{modifier:{pattern:RegExp("(^[a-z]\\w*)(?:"+t+"|[<>=()])+(?=\\.)"),lookbehind:!0,inside:e.util.clone(n)},tag:/^[a-z]\w*/,punctuation:/\.$/}},list:{pattern:RegExp("^[*#]+(?:"+t+")?\\s+.+","m"),inside:{modifier:{pattern:RegExp("(^[*#]+)"+t),lookbehind:!0,inside:e.util.clone(n)},punctuation:/^[*#]+/}},table:{pattern:RegExp("^(?:(?:"+t+"|[<>=()^~])+\\.\\s*)?(?:\\|(?:(?:"+t+"|[<>=()^~_]|[\\\\/]\\d+)+\\.)?[^|]*)+\\|","m"),inside:{modifier:{pattern:RegExp("(^|\\|(?:\\r?\\n|\\r)?)(?:"+t+"|[<>=()^~_]|[\\\\/]\\d+)+(?=\\.)"),lookbehind:!0,inside:e.util.clone(n)},punctuation:/\||^\./}},inline:{pattern:RegExp("(\\*\\*|__|\\?\\?|[*_%@+\\-^~])(?:"+t+")?.+?\\1"),inside:{bold:{pattern:RegExp("((^\\*\\*?)(?:"+t+")?).+?(?=\\2)"),lookbehind:!0},italic:{pattern:RegExp("((^__?)(?:"+t+")?).+?(?=\\2)"),lookbehind:!0},cite:{pattern:RegExp("(^\\?\\?(?:"+t+")?).+?(?=\\?\\?)"),lookbehind:!0,alias:"string"},code:{pattern:RegExp("(^@(?:"+t+")?).+?(?=@)"),lookbehind:!0,alias:"keyword"},inserted:{pattern:RegExp("(^\\+(?:"+t+")?).+?(?=\\+)"),lookbehind:!0},deleted:{pattern:RegExp("(^-(?:"+t+")?).+?(?=-)"),lookbehind:!0},span:{pattern:RegExp("(^%(?:"+t+")?).+?(?=%)"),lookbehind:!0},modifier:{pattern:RegExp("(^\\*\\*|__|\\?\\?|[*_%@+\\-^~])"+t),lookbehind:!0,inside:e.util.clone(n)},punctuation:/[*_%?@+\-^~]+/}},"link-ref":{pattern:/^\[[^\]]+\]\S+$/m,inside:{string:{pattern:/(\[)[^\]]+(?=\])/,lookbehind:!0},url:{pattern:/(\])\S+$/,lookbehind:!0},punctuation:/[\[\]]/}},link:{pattern:RegExp('"(?:'+t+')?[^"]+":.+?(?=[^\\w/]?(?:\\s|$))'),inside:{text:{pattern:RegExp('(^"(?:'+t+')?)[^"]+(?=")'),lookbehind:!0},modifier:{pattern:RegExp('(^")'+t),lookbehind:!0,inside:e.util.clone(n)},url:{pattern:/(:).+/,lookbehind:!0},punctuation:/[":]/}},image:{pattern:RegExp("!(?:"+t+"|[<>=()])*[^!\\s()]+(?:\\([^)]+\\))?!(?::.+?(?=[^\\w/]?(?:\\s|$)))?"),inside:{source:{pattern:RegExp("(^!(?:"+t+"|[<>=()])*)[^!\\s()]+(?:\\([^)]+\\))?(?=!)"),lookbehind:!0,alias:"url"},modifier:{pattern:RegExp("(^!)(?:"+t+"|[<>=()])+"),lookbehind:!0,inside:e.util.clone(n)},url:{pattern:/(:).+/,lookbehind:!0},punctuation:/[!:]/}},footnote:{pattern:/\b\[\d+\]/,alias:"comment",inside:{punctuation:/\[|\]/}},acronym:{pattern:/\b[A-Z\d]+\([^)]+\)/,inside:{comment:{pattern:/(\()[^)]+(?=\))/,lookbehind:!0},punctuation:/[()]/}},mark:{pattern:/\b\((TM|R|C)\)/,alias:"comment",inside:{punctuation:/[()]/}}}}});var a={inline:e.util.clone(e.languages.textile.phrase.inside.inline),link:e.util.clone(e.languages.textile.phrase.inside.link),image:e.util.clone(e.languages.textile.phrase.inside.image),footnote:e.util.clone(e.languages.textile.phrase.inside.footnote),acronym:e.util.clone(e.languages.textile.phrase.inside.acronym),mark:e.util.clone(e.languages.textile.phrase.inside.mark)};e.languages.textile.tag.pattern=/<\/?(?!\d)[a-z0-9]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,e.languages.textile.phrase.inside.inline.inside.bold.inside=a,e.languages.textile.phrase.inside.inline.inside.italic.inside=a,e.languages.textile.phrase.inside.inline.inside.inserted.inside=a,e.languages.textile.phrase.inside.inline.inside.deleted.inside=a,e.languages.textile.phrase.inside.inline.inside.span.inside=a,e.languages.textile.phrase.inside.table.inside.inline=a.inline,e.languages.textile.phrase.inside.table.inside.link=a.link,e.languages.textile.phrase.inside.table.inside.image=a.image,e.languages.textile.phrase.inside.table.inside.footnote=a.footnote,e.languages.textile.phrase.inside.table.inside.acronym=a.acronym,e.languages.textile.phrase.inside.table.inside.mark=a.mark}(Prism),Prism.languages.twig={comment:/\{#[\s\S]*?#\}/,tag:{pattern:/\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}/,inside:{ld:{pattern:/^(?:\{\{\-?|\{%\-?\s*\w+)/,inside:{punctuation:/^(?:\{\{|\{%)\-?/,keyword:/\w+/}},rd:{pattern:/\-?(?:%\}|\}\})$/,inside:{punctuation:/.*/}},string:{pattern:/("|')(?:\\?.)*?\1/,inside:{punctuation:/^['"]|['"]$/}},keyword:/\b(?:even|if|odd)\b/,"boolean":/\b(?:true|false|null)\b/,number:/\b-?(?:0x[\dA-Fa-f]+|\d*\.?\d+([Ee][-+]?\d+)?)\b/,operator:[{pattern:/(\s)(?:and|b\-and|b\-xor|b\-or|ends with|in|is|matches|not|or|same as|starts with)(?=\s)/,lookbehind:!0},/[=<>]=?|!=|\*\*?|\/\/?|\?:?|[-+~%|]/],property:/\b[a-zA-Z_][a-zA-Z0-9_]*\b/,punctuation:/[()\[\]{}:.,]/}},other:{pattern:/\S(?:[\s\S]*\S)?/,inside:Prism.languages.markup}},Prism.languages.typescript=Prism.languages.extend("javascript",{keyword:/\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield|module|declare|constructor|string|Function|any|number|boolean|Array|enum)\b/}),Prism.languages.verilog={comment:/\/\/.*|\/\*[\w\W]*?\*\//,string:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,property:/\B\$\w+\b/,constant:/\B`\w+\b/,"function":/[a-z\d_]+(?=\()/i,keyword:/\b(?:alias|and|assert|assign|assume|automatic|before|begin|bind|bins|binsof|bit|break|buf|bufif0|bufif1|byte|class|case|casex|casez|cell|chandle|clocking|cmos|config|const|constraint|context|continue|cover|covergroup|coverpoint|cross|deassign|default|defparam|design|disable|dist|do|edge|else|end|endcase|endclass|endclocking|endconfig|endfunction|endgenerate|endgroup|endinterface|endmodule|endpackage|endprimitive|endprogram|endproperty|endspecify|endsequence|endtable|endtask|enum|event|expect|export|extends|extern|final|first_match|for|force|foreach|forever|fork|forkjoin|function|generate|genvar|highz0|highz1|if|iff|ifnone|ignore_bins|illegal_bins|import|incdir|include|initial|inout|input|inside|instance|int|integer|interface|intersect|join|join_any|join_none|large|liblist|library|local|localparam|logic|longint|macromodule|matches|medium|modport|module|nand|negedge|new|nmos|nor|noshowcancelled|not|notif0|notif1|null|or|output|package|packed|parameter|pmos|posedge|primitive|priority|program|property|protected|pull0|pull1|pulldown|pullup|pulsestyle_onevent|pulsestyle_ondetect|pure|rand|randc|randcase|randsequence|rcmos|real|realtime|ref|reg|release|repeat|return|rnmos|rpmos|rtran|rtranif0|rtranif1|scalared|sequence|shortint|shortreal|showcancelled|signed|small|solve|specify|specparam|static|string|strong0|strong1|struct|super|supply0|supply1|table|tagged|task|this|throughout|time|timeprecision|timeunit|tran|tranif0|tranif1|tri|tri0|tri1|triand|trior|trireg|type|typedef|union|unique|unsigned|use|uwire|var|vectored|virtual|void|wait|wait_order|wand|weak0|weak1|while|wildcard|wire|with|within|wor|xnor|xor)\b/,important:/\b(?:always_latch|always_comb|always_ff|always)\b ?@?/,number:/\B##?\d+|(?:\b\d+)?'[odbh] ?[\da-fzx_?]+|\b\d*[._]?\d+(?:e[-+]?\d+)?/i,operator:/[-+{}^~%*\/?=!<>&|]+/,punctuation:/[[\];(),.:]/},Prism.languages.vhdl={comment:/--.+/,"vhdl-vectors":{pattern:/\b[oxb]"[\da-f_]+"|"[01uxzwlh-]+"/i,alias:"number"},"quoted-function":{pattern:/"\S+?"(?=\()/,alias:"function"},string:/"(?:[^\\\r\n]|\\?(?:\r\n|[\s\S]))*?"/,constant:/\b(?:use|library)\b/i,keyword:/\b(?:'active|'ascending|'base|'delayed|'driving|'driving_value|'event|'high|'image|'instance_name|'last_active|'last_event|'last_value|'left|'leftof|'length|'low|'path_name|'pos|'pred|'quiet|'range|'reverse_range|'right|'rightof|'simple_name|'stable|'succ|'transaction|'val|'value|access|after|alias|all|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|new|next|null|of|on|open|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|report|return|select|severity|shared|signal|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with)\b/i,"boolean":/\b(?:true|false)\b/i,"function":/[a-z0-9_]+(?=\()/i,number:/'[01uxzwlh-]'|\b(?:\d+#[\da-f_.]+#|\d[\d_.]*)(?:e[-+]?\d+)?/i,operator:/[<>]=?|:=|[-+*\/&=]|\b(?:abs|not|mod|rem|sll|srl|sla|sra|rol|ror|and|or|nand|xnor|xor|nor)\b/i,punctuation:/[{}[\];(),.:]/},Prism.languages.vim={string:/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\r\n]|'')*'/,comment:/".*/,"function":/\w+(?=\()/,keyword:/\b(?:ab|abbreviate|abc|abclear|abo|aboveleft|al|all|arga|argadd|argd|argdelete|argdo|arge|argedit|argg|argglobal|argl|arglocal|ar|args|argu|argument|as|ascii|bad|badd|ba|ball|bd|bdelete|be|bel|belowright|bf|bfirst|bl|blast|bm|bmodified|bn|bnext|bN|bNext|bo|botright|bp|bprevious|brea|break|breaka|breakadd|breakd|breakdel|breakl|breaklist|br|brewind|bro|browse|bufdo|b|buffer|buffers|bun|bunload|bw|bwipeout|ca|cabbrev|cabc|cabclear|caddb|caddbuffer|cad|caddexpr|caddf|caddfile|cal|call|cat|catch|cb|cbuffer|cc|ccl|cclose|cd|ce|center|cex|cexpr|cf|cfile|cfir|cfirst|cgetb|cgetbuffer|cgete|cgetexpr|cg|cgetfile|c|change|changes|chd|chdir|che|checkpath|checkt|checktime|cla|clast|cl|clist|clo|close|cmapc|cmapclear|cnew|cnewer|cn|cnext|cN|cNext|cnf|cnfile|cNfcNfile|cnorea|cnoreabbrev|col|colder|colo|colorscheme|comc|comclear|comp|compiler|conf|confirm|con|continue|cope|copen|co|copy|cpf|cpfile|cp|cprevious|cq|cquit|cr|crewind|cuna|cunabbrev|cu|cunmap|cw|cwindow|debugg|debuggreedy|delc|delcommand|d|delete|delf|delfunction|delm|delmarks|diffg|diffget|diffoff|diffpatch|diffpu|diffput|diffsplit|diffthis|diffu|diffupdate|dig|digraphs|di|display|dj|djump|dl|dlist|dr|drop|ds|dsearch|dsp|dsplit|earlier|echoe|echoerr|echom|echomsg|echon|e|edit|el|else|elsei|elseif|em|emenu|endfo|endfor|endf|endfunction|endfun|en|endif|endt|endtry|endw|endwhile|ene|enew|ex|exi|exit|exu|exusage|f|file|files|filetype|fina|finally|fin|find|fini|finish|fir|first|fix|fixdel|fo|fold|foldc|foldclose|folddoc|folddoclosed|foldd|folddoopen|foldo|foldopen|for|fu|fun|function|go|goto|gr|grep|grepa|grepadd|ha|hardcopy|h|help|helpf|helpfind|helpg|helpgrep|helpt|helptags|hid|hide|his|history|ia|iabbrev|iabc|iabclear|if|ij|ijump|il|ilist|imapc|imapclear|in|inorea|inoreabbrev|isearch|isp|isplit|iuna|iunabbrev|iu|iunmap|j|join|ju|jumps|k|keepalt|keepj|keepjumps|kee|keepmarks|laddb|laddbuffer|lad|laddexpr|laddf|laddfile|lan|language|la|last|later|lb|lbuffer|lc|lcd|lch|lchdir|lcl|lclose|let|left|lefta|leftabove|lex|lexpr|lf|lfile|lfir|lfirst|lgetb|lgetbuffer|lgete|lgetexpr|lg|lgetfile|lgr|lgrep|lgrepa|lgrepadd|lh|lhelpgrep|l|list|ll|lla|llast|lli|llist|lmak|lmake|lm|lmap|lmapc|lmapclear|lnew|lnewer|lne|lnext|lN|lNext|lnf|lnfile|lNf|lNfile|ln|lnoremap|lo|loadview|loc|lockmarks|lockv|lockvar|lol|lolder|lop|lopen|lpf|lpfile|lp|lprevious|lr|lrewind|ls|lt|ltag|lu|lunmap|lv|lvimgrep|lvimgrepa|lvimgrepadd|lw|lwindow|mak|make|ma|mark|marks|mat|match|menut|menutranslate|mk|mkexrc|mks|mksession|mksp|mkspell|mkvie|mkview|mkv|mkvimrc|mod|mode|m|move|mzf|mzfile|mz|mzscheme|nbkey|new|n|next|N|Next|nmapc|nmapclear|noh|nohlsearch|norea|noreabbrev|nu|number|nun|nunmap|omapc|omapclear|on|only|o|open|opt|options|ou|ounmap|pc|pclose|ped|pedit|pe|perl|perld|perldo|po|pop|popu|popu|popup|pp|ppop|pre|preserve|prev|previous|p|print|P|Print|profd|profdel|prof|profile|promptf|promptfind|promptr|promptrepl|ps|psearch|pta|ptag|ptf|ptfirst|ptj|ptjump|ptl|ptlast|ptn|ptnext|ptN|ptNext|ptp|ptprevious|ptr|ptrewind|pts|ptselect|pu|put|pw|pwd|pyf|pyfile|py|python|qa|qall|q|quit|quita|quitall|r|read|rec|recover|redi|redir|red|redo|redr|redraw|redraws|redrawstatus|reg|registers|res|resize|ret|retab|retu|return|rew|rewind|ri|right|rightb|rightbelow|rub|ruby|rubyd|rubydo|rubyf|rubyfile|ru|runtime|rv|rviminfo|sal|sall|san|sandbox|sa|sargument|sav|saveas|sba|sball|sbf|sbfirst|sbl|sblast|sbm|sbmodified|sbn|sbnext|sbN|sbNext|sbp|sbprevious|sbr|sbrewind|sb|sbuffer|scripte|scriptencoding|scrip|scriptnames|se|set|setf|setfiletype|setg|setglobal|setl|setlocal|sf|sfind|sfir|sfirst|sh|shell|sign|sil|silent|sim|simalt|sla|slast|sl|sleep|sm|smagic|sm|smap|smapc|smapclear|sme|smenu|sn|snext|sN|sNext|sni|sniff|sno|snomagic|snor|snoremap|snoreme|snoremenu|sor|sort|so|source|spelld|spelldump|spe|spellgood|spelli|spellinfo|spellr|spellrepall|spellu|spellundo|spellw|spellwrong|sp|split|spr|sprevious|sre|srewind|sta|stag|startg|startgreplace|star|startinsert|startr|startreplace|stj|stjump|st|stop|stopi|stopinsert|sts|stselect|sun|sunhide|sunm|sunmap|sus|suspend|sv|sview|syncbind|t|tab|tabc|tabclose|tabd|tabdo|tabe|tabedit|tabf|tabfind|tabfir|tabfirst|tabl|tablast|tabm|tabmove|tabnew|tabn|tabnext|tabN|tabNext|tabo|tabonly|tabp|tabprevious|tabr|tabrewind|tabs|ta|tag|tags|tc|tcl|tcld|tcldo|tclf|tclfile|te|tearoff|tf|tfirst|th|throw|tj|tjump|tl|tlast|tm|tm|tmenu|tn|tnext|tN|tNext|to|topleft|tp|tprevious|tr|trewind|try|ts|tselect|tu|tu|tunmenu|una|unabbreviate|u|undo|undoj|undojoin|undol|undolist|unh|unhide|unlet|unlo|unlockvar|unm|unmap|up|update|verb|verbose|ve|version|vert|vertical|vie|view|vim|vimgrep|vimgrepa|vimgrepadd|vi|visual|viu|viusage|vmapc|vmapclear|vne|vnew|vs|vsplit|vu|vunmap|wa|wall|wh|while|winc|wincmd|windo|winp|winpos|win|winsize|wn|wnext|wN|wNext|wp|wprevious|wq|wqa|wqall|w|write|ws|wsverb|wv|wviminfo|X|xa|xall|x|xit|xm|xmap|xmapc|xmapclear|xme|xmenu|XMLent|XMLns|xn|xnoremap|xnoreme|xnoremenu|xu|xunmap|y|yank)\b/, +builtin:/\b(?:autocmd|acd|ai|akm|aleph|allowrevins|altkeymap|ambiwidth|ambw|anti|antialias|arab|arabic|arabicshape|ari|arshape|autochdir|autoindent|autoread|autowrite|autowriteall|aw|awa|background|backspace|backup|backupcopy|backupdir|backupext|backupskip|balloondelay|ballooneval|balloonexpr|bdir|bdlay|beval|bex|bexpr|bg|bh|bin|binary|biosk|bioskey|bk|bkc|bomb|breakat|brk|browsedir|bs|bsdir|bsk|bt|bufhidden|buflisted|buftype|casemap|ccv|cdpath|cedit|cfu|ch|charconvert|ci|cin|cindent|cink|cinkeys|cino|cinoptions|cinw|cinwords|clipboard|cmdheight|cmdwinheight|cmp|cms|columns|com|comments|commentstring|compatible|complete|completefunc|completeopt|consk|conskey|copyindent|cot|cpo|cpoptions|cpt|cscopepathcomp|cscopeprg|cscopequickfix|cscopetag|cscopetagorder|cscopeverbose|cspc|csprg|csqf|cst|csto|csverb|cuc|cul|cursorcolumn|cursorline|cwh|debug|deco|def|define|delcombine|dex|dg|dict|dictionary|diff|diffexpr|diffopt|digraph|dip|dir|directory|dy|ea|ead|eadirection|eb|ed|edcompatible|ef|efm|ei|ek|enc|encoding|endofline|eol|ep|equalalways|equalprg|errorbells|errorfile|errorformat|esckeys|et|eventignore|expandtab|exrc|fcl|fcs|fdc|fde|fdi|fdl|fdls|fdm|fdn|fdo|fdt|fen|fenc|fencs|fex|ff|ffs|fileencoding|fileencodings|fileformat|fileformats|fillchars|fk|fkmap|flp|fml|fmr|foldcolumn|foldenable|foldexpr|foldignore|foldlevel|foldlevelstart|foldmarker|foldmethod|foldminlines|foldnestmax|foldtext|formatexpr|formatlistpat|formatoptions|formatprg|fp|fs|fsync|ft|gcr|gd|gdefault|gfm|gfn|gfs|gfw|ghr|gp|grepformat|grepprg|gtl|gtt|guicursor|guifont|guifontset|guifontwide|guiheadroom|guioptions|guipty|guitablabel|guitabtooltip|helpfile|helpheight|helplang|hf|hh|hi|hidden|highlight|hk|hkmap|hkmapp|hkp|hl|hlg|hls|hlsearch|ic|icon|iconstring|ignorecase|im|imactivatekey|imak|imc|imcmdline|imd|imdisable|imi|iminsert|ims|imsearch|inc|include|includeexpr|incsearch|inde|indentexpr|indentkeys|indk|inex|inf|infercase|insertmode|isf|isfname|isi|isident|isk|iskeyword|isprint|joinspaces|js|key|keymap|keymodel|keywordprg|km|kmp|kp|langmap|langmenu|laststatus|lazyredraw|lbr|lcs|linebreak|lines|linespace|lisp|lispwords|listchars|loadplugins|lpl|lsp|lz|macatsui|magic|makeef|makeprg|matchpairs|matchtime|maxcombine|maxfuncdepth|maxmapdepth|maxmem|maxmempattern|maxmemtot|mco|mef|menuitems|mfd|mh|mis|mkspellmem|ml|mls|mm|mmd|mmp|mmt|modeline|modelines|modifiable|modified|more|mouse|mousef|mousefocus|mousehide|mousem|mousemodel|mouses|mouseshape|mouset|mousetime|mp|mps|msm|mzq|mzquantum|nf|nrformats|numberwidth|nuw|odev|oft|ofu|omnifunc|opendevice|operatorfunc|opfunc|osfiletype|pa|para|paragraphs|paste|pastetoggle|patchexpr|patchmode|path|pdev|penc|pex|pexpr|pfn|ph|pheader|pi|pm|pmbcs|pmbfn|popt|preserveindent|previewheight|previewwindow|printdevice|printencoding|printexpr|printfont|printheader|printmbcharset|printmbfont|printoptions|prompt|pt|pumheight|pvh|pvw|qe|quoteescape|readonly|remap|report|restorescreen|revins|rightleft|rightleftcmd|rl|rlc|ro|rs|rtp|ruf|ruler|rulerformat|runtimepath|sbo|sc|scb|scr|scroll|scrollbind|scrolljump|scrolloff|scrollopt|scs|sect|sections|secure|sel|selection|selectmode|sessionoptions|sft|shcf|shellcmdflag|shellpipe|shellquote|shellredir|shellslash|shelltemp|shelltype|shellxquote|shiftround|shiftwidth|shm|shortmess|shortname|showbreak|showcmd|showfulltag|showmatch|showmode|showtabline|shq|si|sidescroll|sidescrolloff|siso|sj|slm|smartcase|smartindent|smarttab|smc|smd|softtabstop|sol|spc|spell|spellcapcheck|spellfile|spelllang|spellsuggest|spf|spl|splitbelow|splitright|sps|sr|srr|ss|ssl|ssop|stal|startofline|statusline|stl|stmp|su|sua|suffixes|suffixesadd|sw|swapfile|swapsync|swb|swf|switchbuf|sws|sxq|syn|synmaxcol|syntax|tabline|tabpagemax|tabstop|tagbsearch|taglength|tagrelative|tagstack|tal|tb|tbi|tbidi|tbis|tbs|tenc|term|termbidi|termencoding|terse|textauto|textmode|textwidth|tgst|thesaurus|tildeop|timeout|timeoutlen|title|titlelen|titleold|titlestring|toolbar|toolbariconsize|top|tpm|tsl|tsr|ttimeout|ttimeoutlen|ttm|tty|ttybuiltin|ttyfast|ttym|ttymouse|ttyscroll|ttytype|tw|tx|uc|ul|undolevels|updatecount|updatetime|ut|vb|vbs|vdir|verbosefile|vfile|viewdir|viewoptions|viminfo|virtualedit|visualbell|vop|wak|warn|wb|wc|wcm|wd|weirdinvert|wfh|wfw|whichwrap|wi|wig|wildchar|wildcharm|wildignore|wildmenu|wildmode|wildoptions|wim|winaltkeys|window|winfixheight|winfixwidth|winheight|winminheight|winminwidth|winwidth|wiv|wiw|wm|wmh|wmnu|wmw|wop|wrap|wrapmargin|wrapscan|writeany|writebackup|writedelay|ww|noacd|noai|noakm|noallowrevins|noaltkeymap|noanti|noantialias|noar|noarab|noarabic|noarabicshape|noari|noarshape|noautochdir|noautoindent|noautoread|noautowrite|noautowriteall|noaw|noawa|nobackup|noballooneval|nobeval|nobin|nobinary|nobiosk|nobioskey|nobk|nobl|nobomb|nobuflisted|nocf|noci|nocin|nocindent|nocompatible|noconfirm|noconsk|noconskey|nocopyindent|nocp|nocscopetag|nocscopeverbose|nocst|nocsverb|nocuc|nocul|nocursorcolumn|nocursorline|nodeco|nodelcombine|nodg|nodiff|nodigraph|nodisable|noea|noeb|noed|noedcompatible|noek|noendofline|noeol|noequalalways|noerrorbells|noesckeys|noet|noex|noexpandtab|noexrc|nofen|nofk|nofkmap|nofoldenable|nogd|nogdefault|noguipty|nohid|nohidden|nohk|nohkmap|nohkmapp|nohkp|nohls|noic|noicon|noignorecase|noim|noimc|noimcmdline|noimd|noincsearch|noinf|noinfercase|noinsertmode|nois|nojoinspaces|nojs|nolazyredraw|nolbr|nolinebreak|nolisp|nolist|noloadplugins|nolpl|nolz|noma|nomacatsui|nomagic|nomh|noml|nomod|nomodeline|nomodifiable|nomodified|nomore|nomousef|nomousefocus|nomousehide|nonu|nonumber|noodev|noopendevice|nopaste|nopi|nopreserveindent|nopreviewwindow|noprompt|nopvw|noreadonly|noremap|norestorescreen|norevins|nori|norightleft|norightleftcmd|norl|norlc|noro|nors|noru|noruler|nosb|nosc|noscb|noscrollbind|noscs|nosecure|nosft|noshellslash|noshelltemp|noshiftround|noshortname|noshowcmd|noshowfulltag|noshowmatch|noshowmode|nosi|nosm|nosmartcase|nosmartindent|nosmarttab|nosmd|nosn|nosol|nospell|nosplitbelow|nosplitright|nospr|nosr|nossl|nosta|nostartofline|nostmp|noswapfile|noswf|nota|notagbsearch|notagrelative|notagstack|notbi|notbidi|notbs|notermbidi|noterse|notextauto|notextmode|notf|notgst|notildeop|notimeout|notitle|noto|notop|notr|nottimeout|nottybuiltin|nottyfast|notx|novb|novisualbell|nowa|nowarn|nowb|noweirdinvert|nowfh|nowfw|nowildmenu|nowinfixheight|nowinfixwidth|nowiv|nowmnu|nowrap|nowrapscan|nowrite|nowriteany|nowritebackup|nows|invacd|invai|invakm|invallowrevins|invaltkeymap|invanti|invantialias|invar|invarab|invarabic|invarabicshape|invari|invarshape|invautochdir|invautoindent|invautoread|invautowrite|invautowriteall|invaw|invawa|invbackup|invballooneval|invbeval|invbin|invbinary|invbiosk|invbioskey|invbk|invbl|invbomb|invbuflisted|invcf|invci|invcin|invcindent|invcompatible|invconfirm|invconsk|invconskey|invcopyindent|invcp|invcscopetag|invcscopeverbose|invcst|invcsverb|invcuc|invcul|invcursorcolumn|invcursorline|invdeco|invdelcombine|invdg|invdiff|invdigraph|invdisable|invea|inveb|inved|invedcompatible|invek|invendofline|inveol|invequalalways|inverrorbells|invesckeys|invet|invex|invexpandtab|invexrc|invfen|invfk|invfkmap|invfoldenable|invgd|invgdefault|invguipty|invhid|invhidden|invhk|invhkmap|invhkmapp|invhkp|invhls|invhlsearch|invic|invicon|invignorecase|invim|invimc|invimcmdline|invimd|invincsearch|invinf|invinfercase|invinsertmode|invis|invjoinspaces|invjs|invlazyredraw|invlbr|invlinebreak|invlisp|invlist|invloadplugins|invlpl|invlz|invma|invmacatsui|invmagic|invmh|invml|invmod|invmodeline|invmodifiable|invmodified|invmore|invmousef|invmousefocus|invmousehide|invnu|invnumber|invodev|invopendevice|invpaste|invpi|invpreserveindent|invpreviewwindow|invprompt|invpvw|invreadonly|invremap|invrestorescreen|invrevins|invri|invrightleft|invrightleftcmd|invrl|invrlc|invro|invrs|invru|invruler|invsb|invsc|invscb|invscrollbind|invscs|invsecure|invsft|invshellslash|invshelltemp|invshiftround|invshortname|invshowcmd|invshowfulltag|invshowmatch|invshowmode|invsi|invsm|invsmartcase|invsmartindent|invsmarttab|invsmd|invsn|invsol|invspell|invsplitbelow|invsplitright|invspr|invsr|invssl|invsta|invstartofline|invstmp|invswapfile|invswf|invta|invtagbsearch|invtagrelative|invtagstack|invtbi|invtbidi|invtbs|invtermbidi|invterse|invtextauto|invtextmode|invtf|invtgst|invtildeop|invtimeout|invtitle|invto|invtop|invtr|invttimeout|invttybuiltin|invttyfast|invtx|invvb|invvisualbell|invwa|invwarn|invwb|invweirdinvert|invwfh|invwfw|invwildmenu|invwinfixheight|invwinfixwidth|invwiv|invwmnu|invwrap|invwrapscan|invwrite|invwriteany|invwritebackup|invws|t_AB|t_AF|t_al|t_AL|t_bc|t_cd|t_ce|t_Ce|t_cl|t_cm|t_Co|t_cs|t_Cs|t_CS|t_CV|t_da|t_db|t_dl|t_DL|t_EI|t_F1|t_F2|t_F3|t_F4|t_F5|t_F6|t_F7|t_F8|t_F9|t_fs|t_IE|t_IS|t_k1|t_K1|t_k2|t_k3|t_K3|t_k4|t_K4|t_k5|t_K5|t_k6|t_K6|t_k7|t_K7|t_k8|t_K8|t_k9|t_K9|t_KA|t_kb|t_kB|t_KB|t_KC|t_kd|t_kD|t_KD|t_ke|t_KE|t_KF|t_KG|t_kh|t_KH|t_kI|t_KI|t_KJ|t_KK|t_kl|t_KL|t_kN|t_kP|t_kr|t_ks|t_ku|t_le|t_mb|t_md|t_me|t_mr|t_ms|t_nd|t_op|t_RI|t_RV|t_Sb|t_se|t_Sf|t_SI|t_so|t_sr|t_te|t_ti|t_ts|t_ue|t_us|t_ut|t_vb|t_ve|t_vi|t_vs|t_WP|t_WS|t_xs|t_ZH|t_ZR)\b/,number:/\b(?:0x[\da-f]+|\d+(?:\.\d+)?)\b/i,operator:/\|\||&&|[-+.]=?|[=!](?:[=~][#?]?)?|[<>]=?[#?]?|[*\/%?]|\b(?:is(?:not)?)\b/,punctuation:/[{}[\](),;:]/},Prism.languages.wiki=Prism.languages.extend("markup",{"block-comment":{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0,alias:"comment"},heading:{pattern:/^(=+).+?\1/m,inside:{punctuation:/^=+|=+$/,important:/.+/}},emphasis:{pattern:/('{2,5}).+?\1/,inside:{"bold italic":{pattern:/(''''').+?(?=\1)/,lookbehind:!0},bold:{pattern:/(''')[^'](?:.*?[^'])?(?=\1)/,lookbehind:!0},italic:{pattern:/('')[^'](?:.*?[^'])?(?=\1)/,lookbehind:!0},punctuation:/^''+|''+$/}},hr:{pattern:/^-{4,}/m,alias:"punctuation"},url:[/ISBN +(?:97[89][ -]?)?(?:\d[ -]?){9}[\dx]\b|(?:RFC|PMID) +\d+/i,/\[\[.+?\]\]|\[.+?\]/],variable:[/__[A-Z]+__/,/\{{3}.+?\}{3}/,/\{\{.+?}}/],symbol:[/^#redirect/im,/~{3,5}/],"table-tag":{pattern:/((?:^|[|!])[|!])[^|\r\n]+\|(?!\|)/m,lookbehind:!0,inside:{"table-bar":{pattern:/\|$/,alias:"punctuation"},rest:Prism.languages.markup.tag.inside}},punctuation:/^(?:\{\||\|\}|\|-|[*#:;!|])|\|\||!!/m}),Prism.languages.insertBefore("wiki","tag",{nowiki:{pattern:/<(nowiki|pre|source)\b[\w\W]*?>[\w\W]*?<\/\1>/i,inside:{tag:{pattern:/<(?:nowiki|pre|source)\b[\w\W]*?>|<\/(?:nowiki|pre|source)>/i,inside:Prism.languages.markup.tag.inside}}}}),Prism.languages.xojo={comment:{pattern:/(?:'|\/\/|Rem\b).+/i,inside:{keyword:/^Rem/i}},string:{pattern:/"(?:""|[^"])*"/,greedy:!0},number:[/(?:\b|\B[.-])(?:\d+\.?\d*)(?:E[+-]?\d+)?/i,/&[bchou][a-z\d]+/i],symbol:/#(?:If|Else|ElseIf|Endif|Pragma)\b/i,keyword:/\b(?:AddHandler|App|Array|As(?:signs)?|By(?:Ref|Val)|Break|Call|Case|Catch|Const|Continue|CurrentMethodName|Declare|Dim|Do(?:wnTo)?|Each|Else(?:If)?|End|Exit|Extends|False|Finally|For|Global|If|In|Lib|Loop|Me|Next|Nil|Optional|ParamArray|Raise(?:Event)?|ReDim|Rem|RemoveHandler|Return|Select|Self|Soft|Static|Step|Super|Then|To|True|Try|Ubound|Until|Using|Wend|While)\b/i,operator:/<[=>]?|>=?|[+\-*\/\\^=]|\b(?:AddressOf|And|Ctype|IsA?|Mod|New|Not|Or|Xor|WeakAddressOf)\b/i,punctuation:/[.,;:()]/},Prism.languages.yaml={scalar:{pattern:/([\-:]\s*(![^\s]+)?[ \t]*[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)[^\r\n]+(?:\3[^\r\n]+)*)/,lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:/(\s*(?:^|[:\-,[{\r\n?])[ \t]*(![^\s]+)?[ \t]*)[^\r\n{[\]},#\s]+?(?=\s*:\s)/,lookbehind:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:/([:\-,[{]\s*(![^\s]+)?[ \t]*)(\d{4}-\d\d?-\d\d?([tT]|[ \t]+)\d\d?:\d{2}:\d{2}(\.\d*)?[ \t]*(Z|[-+]\d\d?(:\d{2})?)?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(:\d{2}(\.\d*)?)?)(?=[ \t]*($|,|]|}))/m,lookbehind:!0,alias:"number"},"boolean":{pattern:/([:\-,[{]\s*(![^\s]+)?[ \t]*)(true|false)[ \t]*(?=$|,|]|})/im,lookbehind:!0,alias:"important"},"null":{pattern:/([:\-,[{]\s*(![^\s]+)?[ \t]*)(null|~)[ \t]*(?=$|,|]|})/im,lookbehind:!0,alias:"important"},string:{pattern:/([:\-,[{]\s*(![^\s]+)?[ \t]*)("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')(?=[ \t]*($|,|]|}))/m,lookbehind:!0},number:{pattern:/([:\-,[{]\s*(![^\s]+)?[ \t]*)[+\-]?(0x[\da-f]+|0o[0-7]+|(\d+\.?\d*|\.?\d+)(e[\+\-]?\d+)?|\.inf|\.nan)[ \t]*(?=$|,|]|})/im,lookbehind:!0},tag:/![^\s]+/,important:/[&*][\w]+/,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./}; \ No newline at end of file diff --git a/assets/prism-193ebecb65a347c425ecdb3c4592fd0e.js.gz b/assets/prism-193ebecb65a347c425ecdb3c4592fd0e.js.gz new file mode 100644 index 0000000000..c93e9ad17d Binary files /dev/null and b/assets/prism-193ebecb65a347c425ecdb3c4592fd0e.js.gz differ diff --git a/categories/algo3/index.html b/categories/algo3/index.html new file mode 100644 index 0000000000..4f94e972a5 --- /dev/null +++ b/categories/algo3/index.html @@ -0,0 +1,1807 @@ + + + + + + + + + + + Articles in “Algo3” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Algo3

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/dds/index.html b/categories/dds/index.html new file mode 100644 index 0000000000..8d4d6db5f8 --- /dev/null +++ b/categories/dds/index.html @@ -0,0 +1,1807 @@ + + + + + + + + + + + Articles in “Dds” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Dds

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/enviroment/index.html b/categories/enviroment/index.html new file mode 100644 index 0000000000..a01063feb1 --- /dev/null +++ b/categories/enviroment/index.html @@ -0,0 +1,1809 @@ + + + + + + + + + + + Articles in “Enviroment” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Enviroment

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • Preparacion de un entorno de desarrollo java
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/haskell/index.html b/categories/haskell/index.html new file mode 100644 index 0000000000..dbb146f163 --- /dev/null +++ b/categories/haskell/index.html @@ -0,0 +1,1809 @@ + + + + + + + + + + + Articles in “Haskell” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Haskell

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • Calculo del tipo de una funcion en haskell
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/java/index.html b/categories/java/index.html new file mode 100644 index 0000000000..c14f78a1e2 --- /dev/null +++ b/categories/java/index.html @@ -0,0 +1,1809 @@ + + + + + + + + + + + Articles in “Java” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Java

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • Preparacion de un entorno de desarrollo java
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/paradigmas/index.html b/categories/paradigmas/index.html new file mode 100644 index 0000000000..995a977c79 --- /dev/null +++ b/categories/paradigmas/index.html @@ -0,0 +1,1807 @@ + + + + + + + + + + + Articles in “Paradigmas” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Paradigmas

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/python/index.html b/categories/python/index.html new file mode 100644 index 0000000000..5e96a3769c --- /dev/null +++ b/categories/python/index.html @@ -0,0 +1,1807 @@ + + + + + + + + + + + Articles in “Python” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Python

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/reliability_engineering/index.html b/categories/reliability_engineering/index.html new file mode 100644 index 0000000000..c58eff9901 --- /dev/null +++ b/categories/reliability_engineering/index.html @@ -0,0 +1,1809 @@ + + + + + + + + + + + Articles in “Reliability_engineering” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Reliability_engineering

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • Robustez de los lenguajes
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/ruby/index.html b/categories/ruby/index.html new file mode 100644 index 0000000000..8b89335bea --- /dev/null +++ b/categories/ruby/index.html @@ -0,0 +1,1807 @@ + + + + + + + + + + + Articles in “Ruby” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Ruby

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/scala/index.html b/categories/scala/index.html new file mode 100644 index 0000000000..bb1ea831e0 --- /dev/null +++ b/categories/scala/index.html @@ -0,0 +1,1811 @@ + + + + + + + + + + + Articles in “Scala” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Scala

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • Macros en Scala
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    • Robustez de los lenguajes
    • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/tadp/index.html b/categories/tadp/index.html new file mode 100644 index 0000000000..4c614116b7 --- /dev/null +++ b/categories/tadp/index.html @@ -0,0 +1,1807 @@ + + + + + + + + + + + Articles in “Tadp” + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articles for category: Tadp

    + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/circle.yml b/circle.yml new file mode 100644 index 0000000000..a7bf8b24f1 --- /dev/null +++ b/circle.yml @@ -0,0 +1,44 @@ +version: 2 +jobs: + build: + docker: + - image: circleci/ruby:2.7.2-node-browsers + environment: + TZ: "/usr/share/zoneinfo/America/Argentina/Buenos_Aires" + paralelism: 2 + steps: + - run: git config --global user.email "bot@uqbar.org" + - run: git config --global user.name "UqbarBot" + - checkout + - run: + name: APT Installs + command: | + sudo apt-get --allow-releaseinfo-change update + sudo apt-get update + sudo apt-get install build-essential patch + sudo apt-get install ruby-dev zlib1g-dev liblzma-dev libgmp-dev cmake + - run: + name: Setup nvm and npm + command: | + yarn install + - run: + name: Install Rake + command: gem install rake + - run: + name: Install dependencies + command: bundle install --jobs=10 --retry=3 + - run: + name: Test + command: bundle exec jekyll build + - run: + name: Publishing + command: bundle exec rake publish + +workflows: + version: 2 + build: + jobs: + - build: + filters: + branches: + only: master \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000..5fea449853 Binary files /dev/null and b/favicon.ico differ diff --git a/humans.txt b/humans.txt new file mode 100644 index 0000000000..a8ba2404c8 --- /dev/null +++ b/humans.txt @@ -0,0 +1,11 @@ +/* TEAM */ + +Owner & Developer: Your Name +Site: yoursite.com +Location: Your Location, Country + +/* SITE */ + +Standards: HTML5, CSS3 +Components: Modernizr, jQuery, Web Font Loader, HeadJS, highlight.js, Foundation by ZURB, Foundation Icon Fonts +Software: Ruby, Rake, Jekyll, Jekyll::AssetsPlugin, Sprockets, Sass, Uglifier diff --git a/img/404_img.jpg b/img/404_img.jpg new file mode 100644 index 0000000000..06181cd442 Binary files /dev/null and b/img/404_img.jpg differ diff --git a/img/css-rule.gif b/img/css-rule.gif new file mode 100644 index 0000000000..3814c27354 Binary files /dev/null and b/img/css-rule.gif differ diff --git a/img/featured_star.png b/img/featured_star.png new file mode 100644 index 0000000000..59640b892b Binary files /dev/null and b/img/featured_star.png differ diff --git a/img/languages/ES6-ecmascript6-logo.jpg b/img/languages/ES6-ecmascript6-logo.jpg new file mode 100644 index 0000000000..400bcd8f3f Binary files /dev/null and b/img/languages/ES6-ecmascript6-logo.jpg differ diff --git a/img/languages/JDK-install.png b/img/languages/JDK-install.png new file mode 100644 index 0000000000..0eb6e50762 Binary files /dev/null and b/img/languages/JDK-install.png differ diff --git a/img/languages/Java_logo.png b/img/languages/Java_logo.png new file mode 100644 index 0000000000..a0ab329b8b Binary files /dev/null and b/img/languages/Java_logo.png differ diff --git a/img/languages/React-logo.png b/img/languages/React-logo.png new file mode 100644 index 0000000000..59e15b9311 Binary files /dev/null and b/img/languages/React-logo.png differ diff --git a/img/languages/Xtend.png b/img/languages/Xtend.png new file mode 100644 index 0000000000..c9616d8009 Binary files /dev/null and b/img/languages/Xtend.png differ diff --git a/img/languages/android-logo.png b/img/languages/android-logo.png new file mode 100644 index 0000000000..ef505f5f65 Binary files /dev/null and b/img/languages/android-logo.png differ diff --git a/img/languages/angular.png b/img/languages/angular.png new file mode 100644 index 0000000000..73d4474bbd Binary files /dev/null and b/img/languages/angular.png differ diff --git a/img/languages/angular1.png b/img/languages/angular1.png new file mode 100644 index 0000000000..73d4474bbd Binary files /dev/null and b/img/languages/angular1.png differ diff --git a/img/languages/angularJS.png b/img/languages/angularJS.png new file mode 100644 index 0000000000..7591604219 Binary files /dev/null and b/img/languages/angularJS.png differ diff --git a/img/languages/apache-wicket.png b/img/languages/apache-wicket.png new file mode 100644 index 0000000000..7d4d92252c Binary files /dev/null and b/img/languages/apache-wicket.png differ diff --git a/img/languages/creatingNewProject.gif b/img/languages/creatingNewProject.gif new file mode 100644 index 0000000000..9d50efed71 Binary files /dev/null and b/img/languages/creatingNewProject.gif differ diff --git a/img/languages/customizeXtendPerspective.gif b/img/languages/customizeXtendPerspective.gif new file mode 100644 index 0000000000..4e94fa06d8 Binary files /dev/null and b/img/languages/customizeXtendPerspective.gif differ diff --git a/img/languages/eclipse-installer-1.png b/img/languages/eclipse-installer-1.png new file mode 100644 index 0000000000..2dcad4b1b3 Binary files /dev/null and b/img/languages/eclipse-installer-1.png differ diff --git a/img/languages/eclipse-installer-2.png b/img/languages/eclipse-installer-2.png new file mode 100644 index 0000000000..16db4f2593 Binary files /dev/null and b/img/languages/eclipse-installer-2.png differ diff --git a/img/languages/eclipse-installer-4.png b/img/languages/eclipse-installer-4.png new file mode 100644 index 0000000000..a8b22d315c Binary files /dev/null and b/img/languages/eclipse-installer-4.png differ diff --git a/img/languages/eclipseDownload.png b/img/languages/eclipseDownload.png new file mode 100644 index 0000000000..8481c980f2 Binary files /dev/null and b/img/languages/eclipseDownload.png differ diff --git a/img/languages/encodingConfigEclipse.png b/img/languages/encodingConfigEclipse.png new file mode 100644 index 0000000000..cf6f9d54c9 Binary files /dev/null and b/img/languages/encodingConfigEclipse.png differ diff --git a/img/languages/firstClass.gif b/img/languages/firstClass.gif new file mode 100644 index 0000000000..58657959c0 Binary files /dev/null and b/img/languages/firstClass.gif differ diff --git a/img/languages/formattingCode.gif b/img/languages/formattingCode.gif new file mode 100644 index 0000000000..19667cf4ba Binary files /dev/null and b/img/languages/formattingCode.gif differ diff --git a/img/languages/git_clone.gif b/img/languages/git_clone.gif new file mode 100644 index 0000000000..64479287bf Binary files /dev/null and b/img/languages/git_clone.gif differ diff --git a/img/languages/git_clone2.jpg b/img/languages/git_clone2.jpg new file mode 100644 index 0000000000..e655f07ffc Binary files /dev/null and b/img/languages/git_clone2.jpg differ diff --git a/img/languages/git_clone3.png b/img/languages/git_clone3.png new file mode 100644 index 0000000000..9e451b3f90 Binary files /dev/null and b/img/languages/git_clone3.png differ diff --git a/img/languages/git_clone_step1.png b/img/languages/git_clone_step1.png new file mode 100644 index 0000000000..76fb0d0b0f Binary files /dev/null and b/img/languages/git_clone_step1.png differ diff --git a/img/languages/git_clone_step2.png b/img/languages/git_clone_step2.png new file mode 100644 index 0000000000..31eb17695c Binary files /dev/null and b/img/languages/git_clone_step2.png differ diff --git a/img/languages/git_clone_step3.png b/img/languages/git_clone_step3.png new file mode 100644 index 0000000000..5f855e79d8 Binary files /dev/null and b/img/languages/git_clone_step3.png differ diff --git a/img/languages/git_clone_step4.png b/img/languages/git_clone_step4.png new file mode 100644 index 0000000000..27f0439408 Binary files /dev/null and b/img/languages/git_clone_step4.png differ diff --git a/img/languages/grails-logo.jpg b/img/languages/grails-logo.jpg new file mode 100644 index 0000000000..24499d3341 Binary files /dev/null and b/img/languages/grails-logo.jpg differ diff --git a/img/languages/installedJREConfigEclipse.png b/img/languages/installedJREConfigEclipse.png new file mode 100644 index 0000000000..87470ee0fb Binary files /dev/null and b/img/languages/installedJREConfigEclipse.png differ diff --git a/img/languages/jdkConfigEclipse.gif b/img/languages/jdkConfigEclipse.gif new file mode 100644 index 0000000000..161b719aef Binary files /dev/null and b/img/languages/jdkConfigEclipse.gif differ diff --git a/img/languages/jdkVsJre.png b/img/languages/jdkVsJre.png new file mode 100644 index 0000000000..a8757eebfc Binary files /dev/null and b/img/languages/jdkVsJre.png differ diff --git a/img/languages/mavenConfigurationEclipse.png b/img/languages/mavenConfigurationEclipse.png new file mode 100644 index 0000000000..241938ffaf Binary files /dev/null and b/img/languages/mavenConfigurationEclipse.png differ diff --git a/img/languages/mavenLogo.png b/img/languages/mavenLogo.png new file mode 100644 index 0000000000..139f08c3f9 Binary files /dev/null and b/img/languages/mavenLogo.png differ diff --git a/img/languages/potentialProgrammingProblemsConfigEclipse.png b/img/languages/potentialProgrammingProblemsConfigEclipse.png new file mode 100644 index 0000000000..e4455172ab Binary files /dev/null and b/img/languages/potentialProgrammingProblemsConfigEclipse.png differ diff --git a/img/languages/project_maven.png b/img/languages/project_maven.png new file mode 100644 index 0000000000..3754053ae4 Binary files /dev/null and b/img/languages/project_maven.png differ diff --git a/img/languages/spellConfigurationEclipse.png b/img/languages/spellConfigurationEclipse.png new file mode 100644 index 0000000000..97cfd41262 Binary files /dev/null and b/img/languages/spellConfigurationEclipse.png differ diff --git a/img/languages/uqbar-arena-logo.png b/img/languages/uqbar-arena-logo.png new file mode 100644 index 0000000000..c66a1aa1f1 Binary files /dev/null and b/img/languages/uqbar-arena-logo.png differ diff --git a/img/languages/xtend-install.png b/img/languages/xtend-install.png new file mode 100644 index 0000000000..a0c37bc769 Binary files /dev/null and b/img/languages/xtend-install.png differ diff --git a/img/languages/xtendAbstractClassesAndMethods.gif b/img/languages/xtendAbstractClassesAndMethods.gif new file mode 100644 index 0000000000..8c3ae48450 Binary files /dev/null and b/img/languages/xtendAbstractClassesAndMethods.gif differ diff --git a/img/languages/xtendExtensionMethod.gif b/img/languages/xtendExtensionMethod.gif new file mode 100644 index 0000000000..6f0246b6f6 Binary files /dev/null and b/img/languages/xtendExtensionMethod.gif differ diff --git a/img/languages/xtendInheritanceShort.gif b/img/languages/xtendInheritanceShort.gif new file mode 100644 index 0000000000..2964119964 Binary files /dev/null and b/img/languages/xtendInheritanceShort.gif differ diff --git a/img/languages/xtendItImplicitVariable.png b/img/languages/xtendItImplicitVariable.png new file mode 100644 index 0000000000..f8e7c1485f Binary files /dev/null and b/img/languages/xtendItImplicitVariable.png differ diff --git a/img/languages/xtendTypeInference.gif b/img/languages/xtendTypeInference.gif new file mode 100644 index 0000000000..0ef20856e5 Binary files /dev/null and b/img/languages/xtendTypeInference.gif differ diff --git a/img/maven_create_1.png b/img/maven_create_1.png new file mode 100644 index 0000000000..a13787164b Binary files /dev/null and b/img/maven_create_1.png differ diff --git a/img/proyecto-uqbarwiki.png b/img/proyecto-uqbarwiki.png new file mode 100644 index 0000000000..2880136b68 Binary files /dev/null and b/img/proyecto-uqbarwiki.png differ diff --git a/img/search.png b/img/search.png new file mode 100644 index 0000000000..d24f0328e3 Binary files /dev/null and b/img/search.png differ diff --git a/img/wiki/Android-logo.jpg b/img/wiki/Android-logo.jpg new file mode 100644 index 0000000000..2553432011 Binary files /dev/null and b/img/wiki/Android-logo.jpg differ diff --git a/img/wiki/Arena-Xtend.png b/img/wiki/Arena-Xtend.png new file mode 100644 index 0000000000..ef5354fcf6 Binary files /dev/null and b/img/wiki/Arena-Xtend.png differ diff --git a/img/wiki/Arena-dependencias.fw.png b/img/wiki/Arena-dependencias.fw.png new file mode 100644 index 0000000000..9d4760429b Binary files /dev/null and b/img/wiki/Arena-dependencias.fw.png differ diff --git a/img/wiki/ArquitecturaHBase.png b/img/wiki/ArquitecturaHBase.png new file mode 100644 index 0000000000..59a60ef81b Binary files /dev/null and b/img/wiki/ArquitecturaHBase.png differ diff --git a/img/wiki/ChoiceRefactoring-1-300x271.png b/img/wiki/ChoiceRefactoring-1-300x271.png new file mode 100644 index 0000000000..d14015be95 Binary files /dev/null and b/img/wiki/ChoiceRefactoring-1-300x271.png differ diff --git a/img/wiki/ChoiceRefactoring-2-300x271.png b/img/wiki/ChoiceRefactoring-2-300x271.png new file mode 100644 index 0000000000..048918c61f Binary files /dev/null and b/img/wiki/ChoiceRefactoring-2-300x271.png differ diff --git a/img/wiki/ChoiceRefactoring.png b/img/wiki/ChoiceRefactoring.png new file mode 100644 index 0000000000..9a0eedb92d Binary files /dev/null and b/img/wiki/ChoiceRefactoring.png differ diff --git a/img/wiki/CollectionHierarchy.png b/img/wiki/CollectionHierarchy.png new file mode 100644 index 0000000000..582d172673 Binary files /dev/null and b/img/wiki/CollectionHierarchy.png differ diff --git a/img/wiki/Compiler-Java-Eclipse.png b/img/wiki/Compiler-Java-Eclipse.png new file mode 100644 index 0000000000..3fe56953e0 Binary files /dev/null and b/img/wiki/Compiler-Java-Eclipse.png differ diff --git a/img/wiki/ConfiguracionXtendParaGrails.png b/img/wiki/ConfiguracionXtendParaGrails.png new file mode 100644 index 0000000000..864c6f6afa Binary files /dev/null and b/img/wiki/ConfiguracionXtendParaGrails.png differ diff --git a/img/wiki/ConfiguracionXtendParaGrails2.png b/img/wiki/ConfiguracionXtendParaGrails2.png new file mode 100644 index 0000000000..4220cd716f Binary files /dev/null and b/img/wiki/ConfiguracionXtendParaGrails2.png differ diff --git a/img/wiki/Css-rule.gif b/img/wiki/Css-rule.gif new file mode 100644 index 0000000000..fce62741c5 Binary files /dev/null and b/img/wiki/Css-rule.gif differ diff --git a/img/wiki/Curso-cantidadInscriptos.png b/img/wiki/Curso-cantidadInscriptos.png new file mode 100644 index 0000000000..e2240ddf81 Binary files /dev/null and b/img/wiki/Curso-cantidadInscriptos.png differ diff --git a/img/wiki/DdC-conoce.png b/img/wiki/DdC-conoce.png new file mode 100644 index 0000000000..225a05e64a Binary files /dev/null and b/img/wiki/DdC-conoce.png differ diff --git a/img/wiki/DdC-hereda.png b/img/wiki/DdC-hereda.png new file mode 100644 index 0000000000..c88ccfa654 Binary files /dev/null and b/img/wiki/DdC-hereda.png differ diff --git a/img/wiki/DdC-implementa.png b/img/wiki/DdC-implementa.png new file mode 100644 index 0000000000..44e586fe25 Binary files /dev/null and b/img/wiki/DdC-implementa.png differ diff --git a/img/wiki/DdC-usa.png b/img/wiki/DdC-usa.png new file mode 100644 index 0000000000..d84963e5c3 Binary files /dev/null and b/img/wiki/DdC-usa.png differ diff --git a/img/wiki/EjemploCursosAlumnos.png b/img/wiki/EjemploCursosAlumnos.png new file mode 100644 index 0000000000..5a2b0b6b4f Binary files /dev/null and b/img/wiki/EjemploCursosAlumnos.png differ diff --git a/img/wiki/ErrorPluginExcecution.jpg b/img/wiki/ErrorPluginExcecution.jpg new file mode 100644 index 0000000000..776d33bc8f Binary files /dev/null and b/img/wiki/ErrorPluginExcecution.jpg differ diff --git a/img/wiki/ErrorPluginExecutionQuickFix.jpg b/img/wiki/ErrorPluginExecutionQuickFix.jpg new file mode 100644 index 0000000000..445f66e9b5 Binary files /dev/null and b/img/wiki/ErrorPluginExecutionQuickFix.jpg differ diff --git a/img/wiki/ErrorPluginexecutionDiscover.jpg b/img/wiki/ErrorPluginexecutionDiscover.jpg new file mode 100644 index 0000000000..36f8df063d Binary files /dev/null and b/img/wiki/ErrorPluginexecutionDiscover.jpg differ diff --git a/img/wiki/Framework.png b/img/wiki/Framework.png new file mode 100644 index 0000000000..5399892825 Binary files /dev/null and b/img/wiki/Framework.png differ diff --git a/img/wiki/Hbase_logo.png b/img/wiki/Hbase_logo.png new file mode 100644 index 0000000000..ac799246fc Binary files /dev/null and b/img/wiki/Hbase_logo.png differ diff --git a/img/wiki/JDKandJREandJVM.png b/img/wiki/JDKandJREandJVM.png new file mode 100644 index 0000000000..5e26989c0e Binary files /dev/null and b/img/wiki/JDKandJREandJVM.png differ diff --git a/img/wiki/JDKvsJRE.png b/img/wiki/JDKvsJRE.png new file mode 100644 index 0000000000..e2b3d65f6d Binary files /dev/null and b/img/wiki/JDKvsJRE.png differ diff --git a/img/wiki/Kotlin_JDK_JRE.png b/img/wiki/Kotlin_JDK_JRE.png new file mode 100644 index 0000000000..51f49f4fa6 Binary files /dev/null and b/img/wiki/Kotlin_JDK_JRE.png differ diff --git a/img/wiki/Kotlin_logo.png b/img/wiki/Kotlin_logo.png new file mode 100644 index 0000000000..8790f49ca4 Binary files /dev/null and b/img/wiki/Kotlin_logo.png differ diff --git a/img/wiki/Libreria.png b/img/wiki/Libreria.png new file mode 100644 index 0000000000..25470b2b34 Binary files /dev/null and b/img/wiki/Libreria.png differ diff --git a/img/wiki/Maven2.png b/img/wiki/Maven2.png new file mode 100644 index 0000000000..44d29e632b Binary files /dev/null and b/img/wiki/Maven2.png differ diff --git a/img/wiki/ObjetoCursoDesnormalizado.png b/img/wiki/ObjetoCursoDesnormalizado.png new file mode 100644 index 0000000000..e2e90015ea Binary files /dev/null and b/img/wiki/ObjetoCursoDesnormalizado.png differ diff --git a/img/wiki/ObjetoCursoNormalizado.png b/img/wiki/ObjetoCursoNormalizado.png new file mode 100644 index 0000000000..a86c063709 Binary files /dev/null and b/img/wiki/ObjetoCursoNormalizado.png differ diff --git a/img/wiki/ObserverPharo.png b/img/wiki/ObserverPharo.png new file mode 100644 index 0000000000..cf6f426da5 Binary files /dev/null and b/img/wiki/ObserverPharo.png differ diff --git a/img/wiki/Operaciones-de-Traits.png b/img/wiki/Operaciones-de-Traits.png new file mode 100644 index 0000000000..ab45dead3f Binary files /dev/null and b/img/wiki/Operaciones-de-Traits.png differ diff --git a/img/wiki/Palitos_de_Queso.jpg b/img/wiki/Palitos_de_Queso.jpg new file mode 100644 index 0000000000..0262bc85cf Binary files /dev/null and b/img/wiki/Palitos_de_Queso.jpg differ diff --git a/img/wiki/Pdep-colecciones-1.PNG b/img/wiki/Pdep-colecciones-1.PNG new file mode 100644 index 0000000000..b0dacb8f7c Binary files /dev/null and b/img/wiki/Pdep-colecciones-1.PNG differ diff --git a/img/wiki/Pdep-colecciones-2.PNG b/img/wiki/Pdep-colecciones-2.PNG new file mode 100644 index 0000000000..6fceb6a7a8 Binary files /dev/null and b/img/wiki/Pdep-colecciones-2.PNG differ diff --git a/img/wiki/Pdep-colecciones-3.PNG b/img/wiki/Pdep-colecciones-3.PNG new file mode 100644 index 0000000000..62c8133111 Binary files /dev/null and b/img/wiki/Pdep-colecciones-3.PNG differ diff --git a/img/wiki/Pdep-colecciones-4.PNG b/img/wiki/Pdep-colecciones-4.PNG new file mode 100644 index 0000000000..2cd7de8628 Binary files /dev/null and b/img/wiki/Pdep-colecciones-4.PNG differ diff --git a/img/wiki/PharoParaOzonosos-Camion.png b/img/wiki/PharoParaOzonosos-Camion.png new file mode 100644 index 0000000000..219ae92fe6 Binary files /dev/null and b/img/wiki/PharoParaOzonosos-Camion.png differ diff --git a/img/wiki/PharoParaOzonosos-ClaseCreada.png b/img/wiki/PharoParaOzonosos-ClaseCreada.png new file mode 100644 index 0000000000..957638efd1 Binary files /dev/null and b/img/wiki/PharoParaOzonosos-ClaseCreada.png differ diff --git a/img/wiki/PharoParaOzonosos-CreandoUnMetodo.png b/img/wiki/PharoParaOzonosos-CreandoUnMetodo.png new file mode 100644 index 0000000000..c15b14bcb3 Binary files /dev/null and b/img/wiki/PharoParaOzonosos-CreandoUnMetodo.png differ diff --git a/img/wiki/PharoParaOzonosos-MetodoCreado.png b/img/wiki/PharoParaOzonosos-MetodoCreado.png new file mode 100644 index 0000000000..d1b02c009a Binary files /dev/null and b/img/wiki/PharoParaOzonosos-MetodoCreado.png differ diff --git a/img/wiki/PharoParaOzonosos-PaqueteCreado.png b/img/wiki/PharoParaOzonosos-PaqueteCreado.png new file mode 100644 index 0000000000..42753946df Binary files /dev/null and b/img/wiki/PharoParaOzonosos-PaqueteCreado.png differ diff --git a/img/wiki/PharoParaOzonosos-SystemBrowser.png b/img/wiki/PharoParaOzonosos-SystemBrowser.png new file mode 100644 index 0000000000..6ab028206e Binary files /dev/null and b/img/wiki/PharoParaOzonosos-SystemBrowser.png differ diff --git a/img/wiki/PharoParaOzonosos-SystemBrowserSections.png b/img/wiki/PharoParaOzonosos-SystemBrowserSections.png new file mode 100644 index 0000000000..58e320b5b6 Binary files /dev/null and b/img/wiki/PharoParaOzonosos-SystemBrowserSections.png differ diff --git a/img/wiki/PharoParaOzonosos-Workspace-Menu.png b/img/wiki/PharoParaOzonosos-Workspace-Menu.png new file mode 100644 index 0000000000..fd2d564411 Binary files /dev/null and b/img/wiki/PharoParaOzonosos-Workspace-Menu.png differ diff --git a/img/wiki/PharoParaOzonosos-Workspace.png b/img/wiki/PharoParaOzonosos-Workspace.png new file mode 100644 index 0000000000..e683532d78 Binary files /dev/null and b/img/wiki/PharoParaOzonosos-Workspace.png differ diff --git a/img/wiki/PharoParaOzonosos-World.png b/img/wiki/PharoParaOzonosos-World.png new file mode 100644 index 0000000000..8d61746eef Binary files /dev/null and b/img/wiki/PharoParaOzonosos-World.png differ diff --git a/img/wiki/PharoScreenshot.7.png b/img/wiki/PharoScreenshot.7.png new file mode 100644 index 0000000000..043b6d8d3f Binary files /dev/null and b/img/wiki/PharoScreenshot.7.png differ diff --git a/img/wiki/Prototipado.png b/img/wiki/Prototipado.png new file mode 100644 index 0000000000..3ab288ed43 Binary files /dev/null and b/img/wiki/Prototipado.png differ diff --git a/img/wiki/RecursionExampleLength.gif b/img/wiki/RecursionExampleLength.gif new file mode 100644 index 0000000000..9332fd89a9 Binary files /dev/null and b/img/wiki/RecursionExampleLength.gif differ diff --git a/img/wiki/RecursionExampleReverse.gif b/img/wiki/RecursionExampleReverse.gif new file mode 100644 index 0000000000..3c2abf9e0e Binary files /dev/null and b/img/wiki/RecursionExampleReverse.gif differ diff --git a/img/wiki/Responsiveness.jpg b/img/wiki/Responsiveness.jpg new file mode 100644 index 0000000000..d42da456c5 Binary files /dev/null and b/img/wiki/Responsiveness.jpg differ diff --git a/img/wiki/RobinMalUsoBooleanos.jpg b/img/wiki/RobinMalUsoBooleanos.jpg new file mode 100644 index 0000000000..b961a115fd Binary files /dev/null and b/img/wiki/RobinMalUsoBooleanos.jpg differ diff --git a/img/wiki/SVN_plugin.png b/img/wiki/SVN_plugin.png new file mode 100644 index 0000000000..60559ba0c7 Binary files /dev/null and b/img/wiki/SVN_plugin.png differ diff --git a/img/wiki/Typeclasses.PNG b/img/wiki/Typeclasses.PNG new file mode 100644 index 0000000000..3b78f9018c Binary files /dev/null and b/img/wiki/Typeclasses.PNG differ diff --git a/img/wiki/VMsComparadas.png b/img/wiki/VMsComparadas.png new file mode 100644 index 0000000000..f31dd8a314 Binary files /dev/null and b/img/wiki/VMsComparadas.png differ diff --git a/img/wiki/VSCsemicolonTS.gif b/img/wiki/VSCsemicolonTS.gif new file mode 100644 index 0000000000..dddfd88da8 Binary files /dev/null and b/img/wiki/VSCsemicolonTS.gif differ diff --git a/img/wiki/Xtend-install-2020.png b/img/wiki/Xtend-install-2020.png new file mode 100644 index 0000000000..91d1bfb013 Binary files /dev/null and b/img/wiki/Xtend-install-2020.png differ diff --git a/img/wiki/Xtend-installation-2020-2.png b/img/wiki/Xtend-installation-2020-2.png new file mode 100644 index 0000000000..0a64010624 Binary files /dev/null and b/img/wiki/Xtend-installation-2020-2.png differ diff --git a/img/wiki/Xtend-installation.png b/img/wiki/Xtend-installation.png new file mode 100644 index 0000000000..9ebb738990 Binary files /dev/null and b/img/wiki/Xtend-installation.png differ diff --git a/img/wiki/Xtend-logo.png b/img/wiki/Xtend-logo.png new file mode 100644 index 0000000000..d9045e0a2c Binary files /dev/null and b/img/wiki/Xtend-logo.png differ diff --git a/img/wiki/android_architecture.png b/img/wiki/android_architecture.png new file mode 100644 index 0000000000..5e9ae689be Binary files /dev/null and b/img/wiki/android_architecture.png differ diff --git a/img/wiki/android_comparacion_desarrollos.png b/img/wiki/android_comparacion_desarrollos.png new file mode 100644 index 0000000000..a6a43af826 Binary files /dev/null and b/img/wiki/android_comparacion_desarrollos.png differ diff --git a/img/wiki/android_compilation_process.png b/img/wiki/android_compilation_process.png new file mode 100644 index 0000000000..db4d534440 Binary files /dev/null and b/img/wiki/android_compilation_process.png differ diff --git a/img/wiki/android_development_environment.png b/img/wiki/android_development_environment.png new file mode 100644 index 0000000000..318a9d41f2 Binary files /dev/null and b/img/wiki/android_development_environment.png differ diff --git a/img/wiki/android_icon_change_1.png b/img/wiki/android_icon_change_1.png new file mode 100644 index 0000000000..f0346a8841 Binary files /dev/null and b/img/wiki/android_icon_change_1.png differ diff --git a/img/wiki/android_icon_change_2.png b/img/wiki/android_icon_change_2.png new file mode 100644 index 0000000000..57ed5c20ad Binary files /dev/null and b/img/wiki/android_icon_change_2.png differ diff --git a/img/wiki/android_icon_change_3.png b/img/wiki/android_icon_change_3.png new file mode 100644 index 0000000000..f1ef671cb6 Binary files /dev/null and b/img/wiki/android_icon_change_3.png differ diff --git a/img/wiki/android_life_cycle.png b/img/wiki/android_life_cycle.png new file mode 100644 index 0000000000..4ce018df21 Binary files /dev/null and b/img/wiki/android_life_cycle.png differ diff --git a/img/wiki/android_life_cycle_2.png b/img/wiki/android_life_cycle_2.png new file mode 100644 index 0000000000..a5182b10ac Binary files /dev/null and b/img/wiki/android_life_cycle_2.png differ diff --git a/img/wiki/android_nativo_vs_web.jpg b/img/wiki/android_nativo_vs_web.jpg new file mode 100644 index 0000000000..bc832561c2 Binary files /dev/null and b/img/wiki/android_nativo_vs_web.jpg differ diff --git a/img/wiki/arena_transaction.png b/img/wiki/arena_transaction.png new file mode 100644 index 0000000000..d0ec20ef43 Binary files /dev/null and b/img/wiki/arena_transaction.png differ diff --git a/img/wiki/arena_transactions_2.png b/img/wiki/arena_transactions_2.png new file mode 100644 index 0000000000..7932452dd9 Binary files /dev/null and b/img/wiki/arena_transactions_2.png differ diff --git a/img/wiki/arena_transactions_3.png b/img/wiki/arena_transactions_3.png new file mode 100644 index 0000000000..093560feac Binary files /dev/null and b/img/wiki/arena_transactions_3.png differ diff --git a/img/wiki/arena_transactions_4.png b/img/wiki/arena_transactions_4.png new file mode 100644 index 0000000000..4bb8c038c0 Binary files /dev/null and b/img/wiki/arena_transactions_4.png differ diff --git a/img/wiki/centralized-application.png b/img/wiki/centralized-application.png new file mode 100644 index 0000000000..9e2e25a9bf Binary files /dev/null and b/img/wiki/centralized-application.png differ diff --git a/img/wiki/downloading-maven-component.gif b/img/wiki/downloading-maven-component.gif new file mode 100644 index 0000000000..203ce97868 Binary files /dev/null and b/img/wiki/downloading-maven-component.gif differ diff --git a/img/wiki/editarPackageJSONVisualStudio.png b/img/wiki/editarPackageJSONVisualStudio.png new file mode 100644 index 0000000000..1c9c0852ef Binary files /dev/null and b/img/wiki/editarPackageJSONVisualStudio.png differ diff --git a/img/wiki/effective-pom.gif b/img/wiki/effective-pom.gif new file mode 100644 index 0000000000..42ac5d553f Binary files /dev/null and b/img/wiki/effective-pom.gif differ diff --git a/img/wiki/extensionesSublime.png b/img/wiki/extensionesSublime.png new file mode 100644 index 0000000000..fb292a006a Binary files /dev/null and b/img/wiki/extensionesSublime.png differ diff --git a/img/wiki/gradle-add-dependency.gif b/img/wiki/gradle-add-dependency.gif new file mode 100644 index 0000000000..aec501081f Binary files /dev/null and b/img/wiki/gradle-add-dependency.gif differ diff --git a/img/wiki/gradle-componenteFallido.png b/img/wiki/gradle-componenteFallido.png new file mode 100644 index 0000000000..ecc568e815 Binary files /dev/null and b/img/wiki/gradle-componenteFallido.png differ diff --git a/img/wiki/gradle-dependencias.png b/img/wiki/gradle-dependencias.png new file mode 100644 index 0000000000..7602522f94 Binary files /dev/null and b/img/wiki/gradle-dependencias.png differ diff --git a/img/wiki/gradle-transitive-dependencies.gif b/img/wiki/gradle-transitive-dependencies.gif new file mode 100644 index 0000000000..1dcccb2f55 Binary files /dev/null and b/img/wiki/gradle-transitive-dependencies.gif differ diff --git a/img/wiki/gradle_logo2.png b/img/wiki/gradle_logo2.png new file mode 100644 index 0000000000..1b6c129766 Binary files /dev/null and b/img/wiki/gradle_logo2.png differ diff --git a/img/wiki/gradle_task.gif b/img/wiki/gradle_task.gif new file mode 100644 index 0000000000..63dda1da6f Binary files /dev/null and b/img/wiki/gradle_task.gif differ diff --git a/img/wiki/headingsMap.gif b/img/wiki/headingsMap.gif new file mode 100644 index 0000000000..5e75b5b400 Binary files /dev/null and b/img/wiki/headingsMap.gif differ diff --git a/img/wiki/hofunctions1.gif b/img/wiki/hofunctions1.gif new file mode 100644 index 0000000000..b8938fb0e6 Binary files /dev/null and b/img/wiki/hofunctions1.gif differ diff --git a/img/wiki/hofunctions2.gif b/img/wiki/hofunctions2.gif new file mode 100644 index 0000000000..6a3831e96f Binary files /dev/null and b/img/wiki/hofunctions2.gif differ diff --git a/img/wiki/home-1.png b/img/wiki/home-1.png new file mode 100644 index 0000000000..0ce9bccf43 Binary files /dev/null and b/img/wiki/home-1.png differ diff --git a/img/wiki/home-2.png b/img/wiki/home-2.png new file mode 100644 index 0000000000..8a82d48173 Binary files /dev/null and b/img/wiki/home-2.png differ diff --git a/img/wiki/home-3.png b/img/wiki/home-3.png new file mode 100644 index 0000000000..b426cd09ad Binary files /dev/null and b/img/wiki/home-3.png differ diff --git a/img/wiki/html5Outliner.gif b/img/wiki/html5Outliner.gif new file mode 100644 index 0000000000..954a05dd7b Binary files /dev/null and b/img/wiki/html5Outliner.gif differ diff --git a/img/wiki/htmlContent.png b/img/wiki/htmlContent.png new file mode 100644 index 0000000000..1e6bda7a42 Binary files /dev/null and b/img/wiki/htmlContent.png differ diff --git a/img/wiki/htmlStructure.png b/img/wiki/htmlStructure.png new file mode 100644 index 0000000000..9c788c7a3b Binary files /dev/null and b/img/wiki/htmlStructure.png differ diff --git a/img/wiki/importProject_02.png b/img/wiki/importProject_02.png new file mode 100644 index 0000000000..5377c4114b Binary files /dev/null and b/img/wiki/importProject_02.png differ diff --git a/img/wiki/importProject_03.png b/img/wiki/importProject_03.png new file mode 100644 index 0000000000..b99a0bcf00 Binary files /dev/null and b/img/wiki/importProject_03.png differ diff --git a/img/wiki/importProject_04.png b/img/wiki/importProject_04.png new file mode 100644 index 0000000000..4cfb17d244 Binary files /dev/null and b/img/wiki/importProject_04.png differ diff --git a/img/wiki/importProject_06.png b/img/wiki/importProject_06.png new file mode 100644 index 0000000000..92c5bd862a Binary files /dev/null and b/img/wiki/importProject_06.png differ diff --git a/img/wiki/importProject_07.png b/img/wiki/importProject_07.png new file mode 100644 index 0000000000..0b20bf0e0b Binary files /dev/null and b/img/wiki/importProject_07.png differ diff --git a/img/wiki/importProject_08.png b/img/wiki/importProject_08.png new file mode 100644 index 0000000000..32e7d5741a Binary files /dev/null and b/img/wiki/importProject_08.png differ diff --git a/img/wiki/importProject_09.png b/img/wiki/importProject_09.png new file mode 100644 index 0000000000..5b4681d9ee Binary files /dev/null and b/img/wiki/importProject_09.png differ diff --git a/img/wiki/importProject_10.png b/img/wiki/importProject_10.png new file mode 100644 index 0000000000..b33206b245 Binary files /dev/null and b/img/wiki/importProject_10.png differ diff --git a/img/wiki/importProject_11.png b/img/wiki/importProject_11.png new file mode 100644 index 0000000000..b32b8e3c3b Binary files /dev/null and b/img/wiki/importProject_11.png differ diff --git a/img/wiki/inlay_hints.gif b/img/wiki/inlay_hints.gif new file mode 100644 index 0000000000..f61f62e56f Binary files /dev/null and b/img/wiki/inlay_hints.gif differ diff --git a/img/wiki/intelliJ-altEnterF2.gif b/img/wiki/intelliJ-altEnterF2.gif new file mode 100644 index 0000000000..3bb9a65dee Binary files /dev/null and b/img/wiki/intelliJ-altEnterF2.gif differ diff --git a/img/wiki/intellij-altEnter.gif b/img/wiki/intellij-altEnter.gif new file mode 100644 index 0000000000..cd50a0be5b Binary files /dev/null and b/img/wiki/intellij-altEnter.gif differ diff --git a/img/wiki/intellij-ctrlCtrl.gif b/img/wiki/intellij-ctrlCtrl.gif new file mode 100644 index 0000000000..6e2a77f5be Binary files /dev/null and b/img/wiki/intellij-ctrlCtrl.gif differ diff --git a/img/wiki/intellij-formatting2.gif b/img/wiki/intellij-formatting2.gif new file mode 100644 index 0000000000..4a2db13149 Binary files /dev/null and b/img/wiki/intellij-formatting2.gif differ diff --git a/img/wiki/intellij-selection.gif b/img/wiki/intellij-selection.gif new file mode 100644 index 0000000000..9cb16f63f6 Binary files /dev/null and b/img/wiki/intellij-selection.gif differ diff --git a/img/wiki/intellij-shiftShift.gif b/img/wiki/intellij-shiftShift.gif new file mode 100644 index 0000000000..96bea501d9 Binary files /dev/null and b/img/wiki/intellij-shiftShift.gif differ diff --git a/img/wiki/intellij_changingBranch.gif b/img/wiki/intellij_changingBranch.gif new file mode 100644 index 0000000000..ecbfa74ef2 Binary files /dev/null and b/img/wiki/intellij_changingBranch.gif differ diff --git a/img/wiki/intellij_import01.png b/img/wiki/intellij_import01.png new file mode 100644 index 0000000000..78a4826441 Binary files /dev/null and b/img/wiki/intellij_import01.png differ diff --git a/img/wiki/kotest-testeo-expresivo.png b/img/wiki/kotest-testeo-expresivo.png new file mode 100644 index 0000000000..990bbc25df Binary files /dev/null and b/img/wiki/kotest-testeo-expresivo.png differ diff --git a/img/wiki/kotest-variable-no-representativa.png b/img/wiki/kotest-variable-no-representativa.png new file mode 100644 index 0000000000..865c4f23b8 Binary files /dev/null and b/img/wiki/kotest-variable-no-representativa.png differ diff --git a/img/wiki/kotlin-abstractClass.gif b/img/wiki/kotlin-abstractClass.gif new file mode 100644 index 0000000000..ec4fadbf61 Binary files /dev/null and b/img/wiki/kotlin-abstractClass.gif differ diff --git a/img/wiki/kotlin-actualizar-gradle.gif b/img/wiki/kotlin-actualizar-gradle.gif new file mode 100644 index 0000000000..a268a414a6 Binary files /dev/null and b/img/wiki/kotlin-actualizar-gradle.gif differ diff --git a/img/wiki/kotlin-ci-gh-actions-badge.gif b/img/wiki/kotlin-ci-gh-actions-badge.gif new file mode 100644 index 0000000000..df4ac8dd05 Binary files /dev/null and b/img/wiki/kotlin-ci-gh-actions-badge.gif differ diff --git a/img/wiki/kotlin-ci-gh-actions-repo.gif b/img/wiki/kotlin-ci-gh-actions-repo.gif new file mode 100644 index 0000000000..7ed971b31f Binary files /dev/null and b/img/wiki/kotlin-ci-gh-actions-repo.gif differ diff --git a/img/wiki/kotlin-constructorInheritance.gif b/img/wiki/kotlin-constructorInheritance.gif new file mode 100644 index 0000000000..b5eeb85e87 Binary files /dev/null and b/img/wiki/kotlin-constructorInheritance.gif differ diff --git a/img/wiki/kotlin-fixMethodReturn.gif b/img/wiki/kotlin-fixMethodReturn.gif new file mode 100644 index 0000000000..716c48476a Binary files /dev/null and b/img/wiki/kotlin-fixMethodReturn.gif differ diff --git a/img/wiki/kotlin-inheritance.gif b/img/wiki/kotlin-inheritance.gif new file mode 100644 index 0000000000..b1f5e2a746 Binary files /dev/null and b/img/wiki/kotlin-inheritance.gif differ diff --git a/img/wiki/kotlin-new-project.png b/img/wiki/kotlin-new-project.png new file mode 100644 index 0000000000..0c99287112 Binary files /dev/null and b/img/wiki/kotlin-new-project.png differ diff --git a/img/wiki/kotlin-nonNullSafe.png b/img/wiki/kotlin-nonNullSafe.png new file mode 100644 index 0000000000..ea91ed0cb9 Binary files /dev/null and b/img/wiki/kotlin-nonNullSafe.png differ diff --git a/img/wiki/kotlin-nueva-clase2.gif b/img/wiki/kotlin-nueva-clase2.gif new file mode 100644 index 0000000000..36eff9ef1e Binary files /dev/null and b/img/wiki/kotlin-nueva-clase2.gif differ diff --git a/img/wiki/kotlin-nullSafeOperatorNotAllowed.png b/img/wiki/kotlin-nullSafeOperatorNotAllowed.png new file mode 100644 index 0000000000..652b783e1a Binary files /dev/null and b/img/wiki/kotlin-nullSafeOperatorNotAllowed.png differ diff --git a/img/wiki/kotlin-stringNotNull.png b/img/wiki/kotlin-stringNotNull.png new file mode 100644 index 0000000000..d3412f42aa Binary files /dev/null and b/img/wiki/kotlin-stringNotNull.png differ diff --git a/img/wiki/kotlin-stringUninitialized1.png b/img/wiki/kotlin-stringUninitialized1.png new file mode 100644 index 0000000000..a730d0637e Binary files /dev/null and b/img/wiki/kotlin-stringUninitialized1.png differ diff --git a/img/wiki/kotlin-typeInference.gif b/img/wiki/kotlin-typeInference.gif new file mode 100644 index 0000000000..670f75dcdb Binary files /dev/null and b/img/wiki/kotlin-typeInference.gif differ diff --git a/img/wiki/list.png b/img/wiki/list.png new file mode 100644 index 0000000000..2352a528a7 Binary files /dev/null and b/img/wiki/list.png differ diff --git a/img/wiki/maven-flow.png b/img/wiki/maven-flow.png new file mode 100644 index 0000000000..3419207e37 Binary files /dev/null and b/img/wiki/maven-flow.png differ diff --git a/img/wiki/maven-m2-build.gif b/img/wiki/maven-m2-build.gif new file mode 100644 index 0000000000..0fd393ca14 Binary files /dev/null and b/img/wiki/maven-m2-build.gif differ diff --git a/img/wiki/maven-plugin-lifecycle.png b/img/wiki/maven-plugin-lifecycle.png new file mode 100644 index 0000000000..cb3ec2a1e1 Binary files /dev/null and b/img/wiki/maven-plugin-lifecycle.png differ diff --git a/img/wiki/maven_local_repo.gif b/img/wiki/maven_local_repo.gif new file mode 100644 index 0000000000..54e0af78c0 Binary files /dev/null and b/img/wiki/maven_local_repo.gif differ diff --git a/img/wiki/mmvc-ejemplo1.png b/img/wiki/mmvc-ejemplo1.png new file mode 100644 index 0000000000..74b79f2e05 Binary files /dev/null and b/img/wiki/mmvc-ejemplo1.png differ diff --git a/img/wiki/mmvc-ejemplo2.png b/img/wiki/mmvc-ejemplo2.png new file mode 100644 index 0000000000..1cae0e70d1 Binary files /dev/null and b/img/wiki/mmvc-ejemplo2.png differ diff --git a/img/wiki/mmvc-ejemplo3.png b/img/wiki/mmvc-ejemplo3.png new file mode 100644 index 0000000000..47d3d33679 Binary files /dev/null and b/img/wiki/mmvc-ejemplo3.png differ diff --git a/img/wiki/mmvc-grafico.png b/img/wiki/mmvc-grafico.png new file mode 100644 index 0000000000..b83bbe3047 Binary files /dev/null and b/img/wiki/mmvc-grafico.png differ diff --git a/img/wiki/modulo.gif b/img/wiki/modulo.gif new file mode 100644 index 0000000000..7bd9cdbe39 Binary files /dev/null and b/img/wiki/modulo.gif differ diff --git a/img/wiki/mvc.jpg b/img/wiki/mvc.jpg new file mode 100644 index 0000000000..703d394131 Binary files /dev/null and b/img/wiki/mvc.jpg differ diff --git a/img/wiki/node_modules_meme.png b/img/wiki/node_modules_meme.png new file mode 100644 index 0000000000..85d34831fc Binary files /dev/null and b/img/wiki/node_modules_meme.png differ diff --git a/img/wiki/peer-to-peer.png b/img/wiki/peer-to-peer.png new file mode 100644 index 0000000000..8561f94f0e Binary files /dev/null and b/img/wiki/peer-to-peer.png differ diff --git a/img/wiki/rich_client_application.jpg b/img/wiki/rich_client_application.jpg new file mode 100644 index 0000000000..3e7009ffff Binary files /dev/null and b/img/wiki/rich_client_application.jpg differ diff --git a/img/wiki/search-maven.gif b/img/wiki/search-maven.gif new file mode 100644 index 0000000000..3864481e18 Binary files /dev/null and b/img/wiki/search-maven.gif differ diff --git a/img/wiki/testeo_mal_nombre_variable.png b/img/wiki/testeo_mal_nombre_variable.png new file mode 100644 index 0000000000..15460b890f Binary files /dev/null and b/img/wiki/testeo_mal_nombre_variable.png differ diff --git a/img/wiki/testeo_mas_expresivo_2.png b/img/wiki/testeo_mas_expresivo_2.png new file mode 100644 index 0000000000..43673c8a7c Binary files /dev/null and b/img/wiki/testeo_mas_expresivo_2.png differ diff --git a/img/wiki/thinking_layout.jpg b/img/wiki/thinking_layout.jpg new file mode 100644 index 0000000000..66ef97a8d4 Binary files /dev/null and b/img/wiki/thinking_layout.jpg differ diff --git a/img/wiki/travisStatusBadge2.gif b/img/wiki/travisStatusBadge2.gif new file mode 100644 index 0000000000..df21c70496 Binary files /dev/null and b/img/wiki/travisStatusBadge2.gif differ diff --git a/img/wiki/ui-twitter.gif b/img/wiki/ui-twitter.gif new file mode 100644 index 0000000000..1e705521c0 Binary files /dev/null and b/img/wiki/ui-twitter.gif differ diff --git a/img/wiki/ui-web-architecture-http-request.gif b/img/wiki/ui-web-architecture-http-request.gif new file mode 100644 index 0000000000..b1d266ab6e Binary files /dev/null and b/img/wiki/ui-web-architecture-http-request.gif differ diff --git a/img/wiki/ui-web-architecture-http-response.gif b/img/wiki/ui-web-architecture-http-response.gif new file mode 100644 index 0000000000..974013016b Binary files /dev/null and b/img/wiki/ui-web-architecture-http-response.gif differ diff --git a/img/wiki/ui-web-architecture-http-response2.gif b/img/wiki/ui-web-architecture-http-response2.gif new file mode 100644 index 0000000000..9965ba6c25 Binary files /dev/null and b/img/wiki/ui-web-architecture-http-response2.gif differ diff --git a/img/wiki/ui-web-arquitectura.png b/img/wiki/ui-web-arquitectura.png new file mode 100644 index 0000000000..24719a6b4d Binary files /dev/null and b/img/wiki/ui-web-arquitectura.png differ diff --git a/img/wiki/unq.png b/img/wiki/unq.png new file mode 100644 index 0000000000..da2756f717 Binary files /dev/null and b/img/wiki/unq.png differ diff --git a/img/wiki/unsam.png b/img/wiki/unsam.png new file mode 100644 index 0000000000..c9abaa35c6 Binary files /dev/null and b/img/wiki/unsam.png differ diff --git a/img/wiki/utn.png b/img/wiki/utn.png new file mode 100644 index 0000000000..06d3476551 Binary files /dev/null and b/img/wiki/utn.png differ diff --git a/img/wiki/xtendJDKvsJRE.png b/img/wiki/xtendJDKvsJRE.png new file mode 100644 index 0000000000..493847e30f Binary files /dev/null and b/img/wiki/xtendJDKvsJRE.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000000..c9d4aabb9a --- /dev/null +++ b/index.html @@ -0,0 +1,236 @@ + + + + + + + + + + + Portada + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +"Generar una forma de pensar crítica, rigurosa, donde no cabe el dogma, la fe ni el principio de autoridad para sustentar un argumento" (1) +
    + +

    Portada

    + +

    ¡Hola!

    + +

    Bienvenidos a la herramienta colaborativa del grupo Uqbar. Somos un grupo de docentes, investigadores y alumnos de diferentes universidades de la Argentina que enseñamos, aprendemos y trabajamos en diferentes temas relacionados con la construcción de software.

    + +

    El objetivo de esta página es proveer un lugar integrado en el cual agrupar y organizar el conocimiento con el que trabajamos, que sirva tanto para compartirlo entre las distintas universidades en las que nos desempeñamos como para la comunidad en general. También nos permite publicar material asociado con las asignaturas pero que muchas veces por motivo de espacio no es posible abordarlo durante la cursada, así que este es el lugar en el que el estudiante curioso puede ir un poquito más allá de lo que podemos alcanzar a ver en clase.

    + +


    + +

    Si sos un estudiante en busca del material de una materia, tal vez te convenga ingresar por uno de estos links:

    + +

    UTN

    + + + +

    UNSAM

    + + + +

    Material adicional

    + +

    Para el que busca algo que vaya más allá de lo visto en las clases aquí hay una lista con algunos artículos sobre otros Temas Interesantes de Programación. Finalmente, otra posibilidad es browsear nuestra colección de propuestas de Herramientas Útiles, que incluye tanto herramientas propias como algunas herramientas de terceros que recomendamos.

    + +

    Discusiones

    + + + +


    +

    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/install.sh b/install.sh new file mode 100755 index 0000000000..bc0b8d54c0 --- /dev/null +++ b/install.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +echo -e "Starting to install of uqbar wiki dependencies \r" +sleep 1 +echo -ne '# (5%)\r' +#Install the requirements for js first +npm install +echo -ne '########### (50%)\r' +sleep 1 +#then run bundle install for installing the required gems +bundle install +echo -ne '####################### (100%)\r' +sleep 1 +echo -ne 'Finishing Installation\n' +sleep 1 +echo -ne '\n' \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..19a54813ff --- /dev/null +++ b/package-lock.json @@ -0,0 +1,12 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "bower": { + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/bower/-/bower-1.8.8.tgz", + "integrity": "sha512-1SrJnXnkP9soITHptSO+ahx3QKp3cVzn8poI6ujqc5SeOkg5iqM1pK9H+DSc2OQ8SnO0jC/NG4Ur/UIwy7574A==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000..306ea04a9a --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "scripts": {}, + "private": true, + "devDependencies": { + "bower": "^1.8.8" + }, + "dependencies": { + "fastclick": "ftlabs/fastclick#1.0.6", + "foundation": "zurb/bower-foundation#5.5.2", + "gist-async": "razor-x/gist-async#2.0.2", + "hawk": "^7.0.10", + "headjs": "headjs/headjs#1.0.3", + "highlightjs": "components/highlightjs#8.8.0", + "hoek": "^6.1.3", + "jquery": "jquery/jquery-dist#^3.0.0", + "jquery-placeholder": "mathiasbynens/jquery-placeholder#~2.0.7", + "jquery.cookie": "carhartl/jquery-cookie#~1.4.0", + "modernizr": "Modernizr/Modernizr#2.8.3", + "normalize-css": "necolas/normalize.css#3.0.3", + "picturefill": "scottjehl/picturefill#2.3.1", + "simple-jekyll-search": "christian-fei/Simple-Jekyll-Search#^1.7.2", + "webfontloader": "typekit/webfontloader#1.6.6" + }, + "engines": { + "yarn": ">= 1.0.0" + } +} diff --git a/redirects.json b/redirects.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/redirects.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000000..eb0536286f --- /dev/null +++ b/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/run_local_jekyll.sh b/run_local_jekyll.sh new file mode 100755 index 0000000000..3a5b2662fa --- /dev/null +++ b/run_local_jekyll.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +bundle install +bundle exec jekyll s --incremental \ No newline at end of file diff --git a/search.json b/search.json new file mode 100644 index 0000000000..bb629cf66e --- /dev/null +++ b/search.json @@ -0,0 +1,3755 @@ +[ + +{ + +"title" : "Page Not Found", +"category" : "", +"tags" : "", +"url" : "/404.html", +"date" : "", +"content" : "Sorry, but the page you were trying to view does not exist." + +} , + +{ + +"title" : "FAQ", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/FAQ.html", +"date" : "", +"content" : "FAQ" + +} , + +{ + +"title" : "Abstraccion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/abstraccion.html", +"date" : "", +"content" : "Programar implica muchas veces manejar grandes cantidades de informacin, un programa es una entidad muy compleja y por lo tanto es muy difcil abarcarlo en su totalidad. Por eso necesitamos herramientas que nos permitan manejar esa complejidad.Gran parte de esas ideas trabajan con el principio de dividir y conquistar, esto es, tomar una parte ms pequea del programa y poder comprenderla olvidndonos momentneamente del resto del programa. Sin embargo, siempre que uno tome una parte de un programa ms grande, esa parte tendr relaciones con otras partes del sistema. Para entenderlo yo debo poder incorporar esas otras partes a mi anlisis pero sin tener que comprender todos sus detalles. Las herramientas que nos permiten eso las denominamos abstracciones.Una abstraccin es una forma de interpretar y conceptualizar lo que resulta ms importante de una entidad compleja, sin tener que tener en cuenta todos sus detalles. Me permite quedarme con lo esencial descartando lo que (para m, en ese momento) es accesorio.Una abstraccin es un concepto o una idea que no est asociado a ningn caso concreto. Abstraer es formar una idea general a partir de casos particulares. En la vida cotidiana usamos abstracciones todo el tiempo y gracias a eso, por ejemplo, podemos saber que una mesa es una mesa ms all de si es cuadrada o redonda, de madera o de plstico, con 4, 3 o 6 patas. Cuando programamos tambin es importante encontrar buenas abstracciones.Cada uno de los paradigmas que vamos a aprender, nos va a brindar sus propias formas de abstraccin. Las abstracciones de cada paradigma van a ser conceptos fundamentales en esta materia. Para los que vienen de programar estructurado, la forma de abstraccin ms conocida es el procedimiento. Un procedimiento permite tomar un conjunto de instrucciones y darles un nombre para poder utilizarla en otro contexto. Quien invoca el procedimiento se concentra en qu es lo que necesita resolver, el procedimiento es el que implementa el cmo se resuelve un determinado problema.La Declaratividad es una forma de abstraccin muy poderosa, que nos permite describir el conocimiento relativo a un problema desentendindonos de los algoritmos necesarios para manipular esa lgica, que son provistos por el motor.Alto nivel y Bajo nivelMuchas veces se habla de lenguajes de alto y bajo nivel, trminos que se refieren al nivel de abstraccin de cada lenguaje. Esta clasificacin no es un blanco y negro, sino que sirve para comparar entre diferentes lenguajes respecto a qu tan cercanas son sus abstracciones a la mquina (bajo nivel) o al programador (alto nivel).A Assembler (trabaja directamente con instrucciones de mquina y los registros de la computadora) podemos considerarlo como de ms bajo nivel que C por ejemplo (que es un lenguaje que se compila a cdigo de mquina y nos permite trabajar con procedimientos y estructuras complejas), sin embargo se puede ir ms a bajo nivel que con Assembler (siempre hay unos y ceros ms abajo) y ms alto nivel que C (todos los lenguajes que usamos en la materia tienen estas caractersticas, un ejemplo de ello es que no necesitamos manejar nuestra propia memoria, existen mecanismos para ello sobre los cuales nos paramos)." + +} , + +{ + +"title" : "Temario de Algoritmos II", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/algo2-temario.html", +"date" : "", +"content" : "Software Entorno Kotlin JDK vs. JRE Gradle Cmo trabajar con TravisPginas Testeo unitario avanzado Cmo corregir un error en runtime, a partir de un ejemplo en githubLinks Sitio oficial de la materia" + +} , + +{ + +"title" : "Temario de Algoritmos III", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/algo3-temario.html", +"date" : "", +"content" : "El sitio oficial de la materia es http://algo3.uqbar-project.orgUnidad 1 - Introduccin a las UI Definiciones Iniciales sobre interfaces de usuario Clasificacin Integracin de la UI en una arquitectura de un sistema de software Elementos a tener en cuenta al programar una UIUnidad 2 - Web EstticoEntornoSolo necesits un editor de texto (nosotros te recomendamos Visual Studio Code) y un navegador (el que vos prefieras)Artculos Introduccin a la arquitectura web HTML CSS Taller de maquetado web Introduccin a SASS ResponsivenessMaterial Pgina de maquetado.Unidad 3 - Web Client Side MVC.Entorno Instalacin de Entorno Angular Manejo de dependencias con NPMMaterial Diapositivas Angular Pgina de Typescript Pgina de Angular Pgina de SpringbootUnidad 4 - Web Client Side FRP.Entorno Instalacin del entorno ReactMaterial Pgina de ReactAnexo A - Cliente pesado. MVC. (deprecado)Este anexo fue deprecado a partir del ao 2020. Dejamos el material por razones histricas.Contenidos principalesEn esta unidad se vern los conceptos principales que permiten organizar el diseo de una interfaz de usuario. Estos conceptos pueden resumirse en: Introduccin a UI: componentes, organizacin espacial de la vista (layout), patrn MVC, binding Navegacin. Relacin entre la navegacin y los casos de uso del sistema. Taller inicial de Arena (hands-on interactivo), a partir de dos ejemplos se cuenta cmo se implementa el layout, algunos componentes visuales y el binding bidireccional, adems del esquema MVC. Application model. Extendiendo el MVC Validaciones y manejo de errores en la UIMaterial de lectura complementario Notas sobre MVC. El patrn MVC tiene multiples interpretaciones, de ellas la que nos parece ms interesante es la que contempla el concepto de Application Model, tambin llamado MMVC, Presentation Model de Martin Fowler, MVVM o MVB (Model-View-Binder). Otras lecturas recomendadas son: Discusin sobre las mltiples interpretaciones y variantes del patrn. Historia del patrn MVC Finalmente una discusin sobre el elemento ms controversial del patrn: el controller. Binding: Vinculacin entre la vista y el modeloEntorno Gua de Componentes Bindings y dems controllers. Binding avanzado Layouts Navegacin y manejo del estado Manejo de Transacciones Qu pasa cuando no tenemos bindingEjemplos en Internet React Rocks Ejemplos de la pgina de ReactAnexo B - Aplicaciones mvilesEntorno Preparacion de un entorno de desarrollo Android Herramientas de desarrollo con AndroidMaterial Introduccin al desarrollo con Android Cambiando el cono / ttulo de la app Ciclo de vida de las actividadesEjemplosKotlin Conversor bsico de millas a kilmetros: primera activity y binding manual versin con Data Binding Listado de pelculas bsico y la versin REST (hay otro branch para ver cmo se trabajaba en REST hasta la SDK 26 Oreo) Primer ejemplo bsico de un servicio REST Prstamos de libros (y de cosas) en base a los contactos del celularJavaPods hacer esta bsqueda en los repositorios de la organizacin UqbarIonic Carga de Productos: se integra con el reconocedor de cdigo de barras del celular. TODO List o lista de cosas para hacer, versin histrica en Ionic 1Ejemplos de Internet Ejemplos de la pgina Developer Android Catlogo de aplicaciones Android de Java2S Ejemplos de Google Repositorios con ejemplos en Googlesource de Android" + +} , + +{ + +"title" : "Amigandonos con el entorno de desarrollo", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/amigandonos-con-el-entorno-de-desarrollo.html", +"date" : "", +"content" : "Algunas buenas prcticas para tener en cuenta:Control de versiones No todos los archivos deben subirse al repo. Como regla general no deberan subir archivos que se puedan generar a partir de otros, por ejemplo: los binarios que se generan a partir del cdigo fuente de ustedes. Ocupan espacio en el repositorio y se corre el riesgo de estar trabajando con versiones desactualizadas. archivos de configuracin propios de cada uno (por ejemplo el .settings que genera el Eclipse). Si alguno tiene una configuracin diferente (que es muy muy muy probable) la van a estar pisando a cada rato, e incluso es probable que les genere conflictos. Nunca deberan subir nuevos fuentes al repositorio sin explicar brevemente qu cambiaron. Si los mensajes son descriptivos (y fix, asdsadsa o arreglo una cosita definitivamente no lo son) rpidamente puedo detectar qu modificaron mis compaeros con slo leer lo que escribieron en los commits. Una buena descripcin me ayuda tambin a entender qu es lo que se modific y por qu razn, especialmente til a la hora de solucionar un conflicto o entender por qu se rompieron los tests. Establecer criterios de trabajo en grupo, algunos muy usados: los tests tienen que estar en verde los tests son de todos y todos somos responsables por mantenerlos si encontramos un bug y no haba un test que lo probaba agregamos uno los tests son rpidos de correr Establecer formas de trabajo y organizar el trabajo nuestro con el de los dems: Cuando empiezo el da primero sincronizo el repositorio para ver los cambios que no tengo en el cdigo Acepto los cambios entrantes y en caso de ser necesario resuelvo conflictos Corro los tests y veo que todo anda sobre ruedas Vuelvo a sincronizar y veo que ya no quedan ni conflictos ni cambios sin aceptar Subo mis cambios al repositorio remoto para que mis compaeros lo vean Esto mismo lo hacemos varias veces al da y antes de subir algo nuevo al repositorio. Siempre corro los tests y si alguno da error, bueno, alguien subi algo indebido. Los tests y el repositorio nos ayudan a entender cundo se rompi y por qu.Git A la hora de ignorar archivos, git nos provee una forma muy sencilla y a la vez poderosa de hacerlo: los .gitignore. Estos son archivos que podemos crear en cualquier carpeta de nuestra estructura (usualmente en el directorio raz) y especificar en ellos qu archivos o patrones deberan quedar fuera del versionado. Cada lnea del .gitignore representa algo que queremos ignorar, por ejemplo enunciado.pdf nos ignorara ese archivo, mientras que *.class va a ignorar todos los .class que tengamos en el directorio actual y en todos sus subdirectorios. Pueden encontrar versiones de .gitignore para la mayora de los lenguajes en https://github.com/github/gitignoreA continuacin te damos una lista de posibles recursos que deberan estar en el archivo .gitignore: /target/ .classpath .project bin generated* .settingsEclipse Cmo organizar los archivos: Convention Over Configuration, el cdigo productivo debera estar en src/main y el cdigo de test en src/test. Qu gano usando estas convenciones? Me corren los tests, me integro con el mundo y eventualmente puedo usar herramientas externas sin tener que configurar nada, ya que respetan estas convenciones (como Maven). Formatear el cdigo! Nunca nos olvidemos de que nuestro cdigo tiene que ser entendible para el resto de la humanidad. Adems, el Eclipse lo hace solo (Ctrl + Shift + F). Utilizacin de packages (paquetes). Es una buena prctica agrupar las clases afines en paquetes para organizar semnticamente el cdigo. No hay una gua firme a seguir con respecto a cmo organizar nuestro cdigo, ya que suele depender del contexto en el cul estamos trabajando, pero es muy comn respetar convenciones para mantener la simplicidad y flexibilidad ahorrando al desarrollador de tomar estas decisiones (Convention over Configuration).Por ejemplo, en un proyecto completo tener paquetes para el dominio, controllers y vista (si correspondiese) es una convencin comn. Cada uno de stos agrupa las clases que tienen un concepto afn. Se podra seguir ahondando en la definicin de subpaquetes agrupando, por ejemplo, por componente:domain/homeregistrationProfile.javaUser.javasettingsCustomPrivacy.javaDefaultPrivacy.javaPrivacy.javaSetting.javaDe esta manera, logramos mayor granularidad en la organizacin de nuestras clases.Otro uso de los paquetes, tambin relacionado con el concepto anteriormente mencionado Convention over Configuration, es el de identificar unvocamente a una aplicacin. Qu significa sto? Que las clases que yo defina formen parte de un meta grupo que los identifique, y as evitar colisiones en los nombres que yo les ponga. Por ejemplo: yo puedo definir la clase Color, pero la api de Java AWT ya define una clase Color.Es por este motivo que se utiliza el dominio de internet de la organizacin, pero dado vuelta. Por ejemplo si trabajamos para Google sera comn encontrar paquetes del estilo com.google.blah. Para el ejemplo de Color, la api de Java la define como java.awt.Color. En nuestro caso podramos usar, por ejemplo: ar.edu.materiaQueCursan.paquete." + +} , + +{ + +"title" : "Android - cómo cambiar ícono y título de la app", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/android-cambiar-icono.html", +"date" : "", +"content" : "ObjetivoPor defecto cuando creamos desde cero una actividad en blanco (Blank Activity) con el Android Studio, nos genera la pgina con una toolbar que muestra el label de la aplicacin.Vista DefaultLa actividad principal define una toolbar&lt;android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"&gt; &lt;LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"&gt; &lt;android.support.v7.widget.Toolbar android:id="@+id/toolbar"El id/toolbar se asigna en el mtodo onCreate() al heredar de AppCompatActivity:override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_pelicula_app_bar) val toolbar = findViewById(R.id.toolbar) as Toolbar setSupportActionBar(toolbar)En nuestro AndroidManifest.xml definimos el label de la aplicacin, mediante una indireccin a una constante:&lt;activity android:name=".ConversorActivity" android:label="@string/app_name" &gt;Esa constante entonces, debemos verla en el archivo res/values/strings.xml:&lt;resources&gt; &lt;string name="app_name"&gt;ConversorApp&lt;/string&gt; Cambiando el ttuloPrimero lo ms sencillo: cambiaremos el nombre de la aplicacin.&lt;resources&gt; &lt;string name="app_name"&gt;Conversor de medidas&lt;/string&gt;Otra opcin es definir una nueva constante y apuntar la propiedad android:label de la activity principal de nuestra aplicacin hacia esta constante, en todo caso dejamos esta tarea al lector.Agregando un cono a nuestra aplicacinSi adems queremos visualizar un cono en la toolbar, debemos modificar el layout default la toolbar ahora debe incluir una imagen y un textview con tamao de ttulo y debemos redefinir la asignacin heredada en el mtodo onCreateEncontrar un conoLa imagen debe tener un cono, hay algunas opciones construirlo nosotros mediante algn programa open-source buscar un cono de licencia libre en InternetVamos por la segunda opcin, ingresamos a esta pgina y seleccionamos , por ejemplo, esta URL: cambiamos el color de fondo y al hacer Download zip vemos que tenemos el mismo png con diferentes tamaos en directorios especiales, uno para cada tipo de resolucin:Copiamos entonces el directorio res a nuestra aplicacin: abrimos el zip extract al directorio donde est la aplicacinAhora s generamos la ImageView y el TextView (activity_conversor.xml):&lt;android.support.v7.widget.Toolbar android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"&gt;&lt;ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_action" /&gt;&lt;TextView android:id="@+id/toolbar" android:layout_width="wrap_content" android:layout_height="wrap_content" /&gt;&lt;/android.support.v7.widget.Toolbar&gt;Hicimos un pequeo cambio: el id/toolbar se lo asignamos al TextView en lugar de a la toolbar.Ejecutamos la aplicacin y nos aparece un mensaje de error en el LogCat:11-10 15:21:52.540 8720-8720/? E/AndroidRuntime: Caused by: java.lang.ClassCastException: android.support.v7.widget.AppCompatTextView cannot be cast to android.support.v7.widget.Toolbar11-10 15:21:52.540 8720-8720/? E/AndroidRuntime: at org.uqbar.conversor.ConversorActivity.onCreate(ConversorActivity.java:23)Ajustamos entonces el mtodo onCreate, para asignar manualmente el valor del textview (ConversorActivity.java):override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_pelicula_app_bar) val toolbar = findViewById(R.id.toolbar) as Toolbar setSupportActionBar(toolbar) toolbar.text = R.string.app_nameAhora s, se visualiza el cono y el ttulo:Pero sera bueno que resaltara un poco ms el ttulo, para eso configuramos la propiedad textSize:&lt;TextView android:id="@+id/toolbar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="? android:attr/textAppearanceLarge"/&gt;Resultado finalY vemos reflejado el cambio en la aplicacin" + +} , + +{ + +"title" : "Ciclo de vida de una actividad en Android", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/android-ciclo-de-vida.html", +"date" : "", +"content" : "Si hablamos del ciclo de vida de las activities de una aplicacin Android, tenemos dos diagramas que lo explican muy bien:FuenteFuenteEsto es importante tenerlo en cuenta para manejar la navegacin entre las actividades, en especial cuando stas comparten datos entre s y se van solapando. Cuando hay actividades que consumen una gran cantidad de recursos, la VM guarda el estado de las actividades que estn en segundo plano y las saca del stack de aplicaciones en memoria para luego volverlas a la vida cuando sea necesario. Esto implica definir cul es ese estado que debe recuperarse o actualizarse cuando la actividad est nuevamente disponible." + +} , + +{ + +"title" : "Preparacion de un entorno de desarrollo android", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/android-instalacion.html", +"date" : "", +"content" : "Download e instalacin baseLa instalacin que nosotros recomendamos es la siguiente: Android Studio Al descargarlo para tu sistema operativo, se abre un asistente En la presentacin, dar Next (Siguiente) Elegir el tipo de instalacin Standard (por defecto) y presionar Next (Siguiente) Se visualizan las opciones elegidas, presionamos Next (Siguiente) y un ltimo Finish hace las descargas necesarias (esperar pacientemente) Android SDK Si vas a trabajar con tu celular como dispositivo de pruebas descargate entonces sa misma versin del SDK (ver ms abajo en Configuraciones) Si vas a trabajar con un emulador, descargate la ltima versin Seguir los pasos que se explican en la URL de descarga (se adapta al sistema operativo e idioma de la mquina) Importante: ConfiguracionesLas configuraciones que te recomendamos son: Si ests familiarizado con los shortcuts del Eclipse: File &gt; Settings &gt; Keymap y en el combo Keymaps seleccionar Eclipse Para hacer las pruebas tienen dos opciones: utilizar un dispositivo Android conectado a USB (algo que recomendamos si tens una mquina con menos de 4GB de memoria) o bien configurar un emulador mediante el Android Virtual Device (AVD). El AVD Manager aparece desde el men Tools &gt; Android &gt; AVD Manager. AVD Name: El nombre que quieran Device: Nexus 5 4.95 1080x1920 420dpi Nougat: Android 7.0 x86_64 Scale: Auto Emulated Performance: Use Host GPU chequeado, Store a snapshot for faster startup deschequeadoIgualmente pueden configurar cualquier otro dispositivo (Phone o Tablet recomendado, no Wear porque tiene caractersticas muy diferentes) IMPORTANTE: Si uss tu celular como dispositivo de pruebas, tienen que coincidir la versin de tu celular con la que vas a configurar en el proyecto.Cmo bajarse los ejemplos Para bajarte los ejemplos o bien uss la opcin Check out project from Version Control y escribs la direccin de los ejemplos, o bien descargs el repositorio Git como un zip y lo descomprims aparte, para luego hacer Import Project. Luego reapuntar el SDK al directorio donde se instal: Tools &gt; Android &gt; SDK Manager: ubican ese directorio Android SDK Location (el que estuvo en el paso $Android_SDK_Path). Adems deben tener instalada alguna API (API Level xx, Revision x, Status: deben marcarla y luego seleccionar Apply). Una vez instalado reiniciar.Troubleshootingcould not find SDK folderImplica que no estn apuntando al SDK que instalaron o bien que no instalaron el Android SDK. Solucin: Tools &gt; Android &gt; SDK Manager, filtran por Android y marcan el SDK Location que corresponda.No se puede ejecutar una app: no devicesSi al correr ven un mensaje de error que indica que no tienen devices, deben configurar un dispositivo para correr la aplicacin Android (Android Virtual Device Manager del men Window) o bien utilizar un dispositivo real conectado a USB.NO System images installed for this targetSi aparece ese error cuando quieren configurar un device y no les habilita el botn Ok, esto implica que falta descargar del Android SDK Manager las VM (imgenes) de los dispositivos que quieren emular. Vayan entonces al Android SDK Manager y fjense qu packages hay disponibles para instalar segn la versin de Android que estn ejecutando.You cant combine swipe dismissal with ActionBar #1Si al correr la aplicacin aparece en el LogCat ese siguiente mensaje revisar si el device es Android Wear, porque no es compatible con los ejemplos.Cmo empezar http://developer.android.com/index.html http://www.vogella.com/android.html Un tutorial de youtube que va bien tranquiloHerramientas de desarrollo Herramientas de desarrollo con AndroidLinks relacionados Temario Algoritmos III" + +} , + +{ + +"title" : "Introducción al desarrollo con Android", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/android-introduccion.html", +"date" : "", +"content" : "Antes de comenzarSi les interesa algo de historia, pueden revisar la pgina de WikipediaQu es AndroidAndroid es un conjunto de tecnologas open source que vienen con un Sistema Operativo (Linux) una Virtual Machine (VM) hecha en Java que se llama Android Runtime (ART, anteriormente tena el nombre Dalvik)sobre la cual corren aplicaciones. Funciona en dispositivos mviles, esto incluye telfonos celulares, tablets, smart TVs, etc.La arquitectura incluye funciones de bajo, medio y alto nivel:En la figura aparecen los servicios ordenados arriba por los de ms alto nivel y yendo hacia los de ms bajo nivel (ms cercanos al hardware del dispositivo)Desarrollar en AndroidPara desarrollar en Android, necesits una SDK o Kit para desarrollar un IDE, que puede ser Android Studio (basado en IntelliJ IDEA) o bien el Eclipse con plugins un entorno (runtime) en el cual instalar y probar tus aplicaciones. Si no ests programando en un dispositivo mvil, hay una diferencia entre la VM en la que desarrolls y la VM en la que efectivamente corre la aplicacin (por eso no vas a poder utilizar LocalDate, entre algunas otras cosas). Las opciones son utilizar un emulador de dispositivos, como el AVD: Android Virtual Device (que promete ser ms liviano que sus predecesores) o Genymotion o bien conectar un dispositivo real con Android a tu mquina y deployar las aplicaciones en ese entorno. Para ms informacin pods ver esta pgina.Algunas consecuencias que surgen es difcil el testeo de una aplicacin aqu ms que nunca es importante poder separar los componentes tecnolgicos y los del negocio, que son ms fciles de testear en forma unitaria, aislada e independiente tambin tenemos que conocer las diferencias entre el emulador y el dispositivo realTipos de Desarrollo en AndroidExisten diferentes formas de desarrollar aplicaciones para dispositivos Android: web adaptado a dispositivos mviles desarrollos hbridos desarrollos nativosVeamos a grandes rasgos de qu se trata cada una.Desarrollo web adaptado a mobileConsiste en adaptar (o crear desde cero) una aplicacin web, es decir HTML + CSS, pero teniendo en mente que va a ser utilizada desde un dispositivo mvil. Por ejemplo la vista puede tener una interfaz tctil la vista ser ms pequea que una computadora de escritorio,o bien que mientras en el escritorio la relacin ancho:alto es 16:9, 4:3,- en el dispositivo mvil la pantalla suele tener por defecto disposicin vertical (pantalla ms alta que ancha), pero podramos querer rotar a una disposicin apaisada (portrait vs. landscape)Para esto existen varias bibliotecas javascript especficas como: Ionic React Native jQT Sencha ExtJSAdems de las limitaciones propias de las aplicaciones web -cuya naturaleza es stateless- requiere estar permanentemente conectado a una red mvil para que la aplicacin pueda funcionar: no hay ningn tipo de procesamiento local. Esto implica que al relegar toda la carga en el servidor se est desaprovechando las capacidades del dispositivo el servidor debe tener capacidad para soportar esa cargaPor otro lado, tiene las ventajas conocidas de las aplicaciones web: administracin centralizada en el servidor, utiliza la misma tecnologa para hacer una nica aplicacin. De todas maneras cabe destacar que el esfuerzo de adaptacin en la interfaz no es menor y depende mucho del tipo de aplicacin.Desarrollo nativoEn el desarrollo nativo se trabaja utilizando la misma tecnologa que provee el dispositivo en el cual se trabaja, esto incluye no slo iOS, Windows Phone, Android sino diferentes tipos de dispositivo y versiones de sistema operativo.Mientras que esto acopla la aplicacin a la plataforma utilizada, y requiere de un desarrollador especializado en esa tecnologa, hay dos grandes ventajas al respecto: se aprovechan al mximo las capacidades y features de ese dispositivo es posible trabajar en forma local (offline) por un cierto tiempo y sincronizar la informacin entre cliente y servidorMs adelante hablaremos de la forma de distribuir las aplicaciones.Desarrollo hbridoEn este tipo de desarrollo se trabaja en parte web y en parte con desarrollo nativo. Tambin suelen incluirse en esta categora los desarrollos generados con productos que soportan varias plataformas mviles (como SAP Fiori, o Appcelerator que son libres y open source). Estos productos limitan los features a utilizar a favor de tener una nica aplicacin global para todas las plataformas.FuenteComparacin entre ArquitecturasEste diagrama comparativo muestra pros y contras entre webmobile apps y aplicaciones nativas.FuenteDistribucin de aplicaciones nativasUno de los grandes dolores de cabeza al construir aplicaciones de cliente rico es que tenan un alto costo la instalacin y el posterior mantenimiento de versiones. Por ese motivo la mayora de los vendedores desarrollaron el concepto de tienda donde se centraliza el deploy de las aplicaciones y la posterior instalacin en cada uno de los clientes. As tenemos Apple Store para iOS, Play Store para Android, Windows Store para Windows Phone, BlackBerry World, etc.La publicacin de nuestra aplicacin en la tienda sigue un circuito de aprobacin previo por parte de los proveedores de la plataforma (en algunos casos como Apple ese circuito puede transformarse en algo bastante burocrtico, que incluya revisiones de cdigo, el pago o la suscripcin como desarrollador a esa plataforma, etc.)La ventaja es que una vez lograda la publicacin, la aplicacin local del dispositivo se encarga de verificar si la aplicacin soporta la versin del aparato, los temas de licenciamiento y la instalacin en s." + +} , + +{ + +"title" : "Instalacion de Entorno Angular", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/angular-instalacion.html", +"date" : "", +"content" : "EntornoEs necesario que instales las siguientes herramientas, en este orden: Si ests en entorno Windows te recomendamos instalarte Git Bash Seguimos con NodeJS. Si ests en entorno Linux/Mac recomendamos que descargues Node desde nvm (Node Version Manager) y luego instales esta versin: nvm install 20.4.0 Si ests en Windows instalate la versin actual Luego NPM (Node Package Manager), con el que vamos a hacer los builds de nuestras aplicaciones. Para familiarizarte con el manejo de dependencias, te dejamos este artculo El Angular CLI (Command line interface) se instala con npm:npm install -g @angular/cliEditor de TextoVisual Studio Code El editor de texto que vamos a soportar en la cursada es Visual Studio Code (hay una versin portable si ests en una mquina sin privilegios de administrador).Los plugins del Visual Studio Code que te recomendamos al 2023 son los que ya instalaste para trabajar con HTML/CSS y los siguientes:Necesarios Path Intellisense (Christian Kohler): autocompletado para archivos de tu file system Auto Import (steoates): ayuda y autocompletado para importar componentes de JS Angular Files (Alexander Ivanichev): agrega un men contextual para crear elementos de Angular Angular Snippets (Version 16) (John Papa): los snippets permiten generar cdigo para servicios y componentes en forma rpida JSON to TS (MariusAlchimavicius): te construye una interfaz de TS en base a la informacin de un JSON Angular Language Service (Angular): autocompletado dentro del template html Material Icon Theme (Philipp Kief) Git Lens (GitKraken), para ver el historial de Git integrado con tu Visual Studio Code ESLint (Microsoft): para disparar el linter de la sintaxis de TSSi tens instalada la extensin Prettier - Code formatter (Prettier) te recomendamos desinstalarla y reemplazarla por Prettier ESLint (Rebecca Vest): es el plugin que vamos a utilizar para aplicar el formato y ejecutar el proceso linter con la sintaxis de la cursada, que define: no usar puntos y coma al final de cada sentencia utilizar comillas simples para strings, un estndar en el mundo Javascript/Typescript evitar imports innecesarios o definiciones de variables que luego no se usen etc.Ms abajo te indicamos los dos archivos que definen esta configuracin: .eslintrc.json y .prettierrc.json.Opcionales Import Cost (Wix): permite calcular cuntos KB pesa cada import Angular2-Switcher (infinity1207): agrega shortcuts para navegar entre .ts, .css, .html Angular2 Inline (Nate Wallace): syntax highlighting y autocompletado de cdigo para componentes Angular inline (que tienen embebido html y css) REST Client (Huachao Mao): para hacer pedidos http desde Visual Studio Code directamente (pods usar POSTMAN, Insomnia o Swagger + navegador tambin)Alternativa a Visual Studio CodeOtra opcin es utilizar Web Storm (de la suite de IntelliJ), si tienen una cuenta de la facultad pueden solicitar una licencia educativa. Solo que como no vamos a aprovechar todas las herramientas de este IDE poderoso quizs convenga ir por el Visual Studio Code.Aprendiendo TypescriptTypescript es el lenguaje de programacin base para Angular. Tranquilo, es muy similar a los lenguajes orientados a objetos en los que ya trabajaste. Para iniciarte o para hacer consultas te dejamos estos links: Documentacin oficial de Typescript: tiene una intro de 5 minutos, otros tutoriales cortos y el Handbook para sacarse dudas Aprendiendo Typescript en 30 minutos: muy buen tutorial para comenzar explicando los conceptos ms salientes Tutorial de Typescript en castellano y PDF: material de consulta en castellano para los interesados El cheatsheet o gua rpida para tener a mano mientras programan Y como typescript es un superconjunto de javascript, siempre conviene tener a mano las funcionalidades de ES6 Tips Typing destructured objects parameters Crear un proyecto Angular desde ceroEn la consola Git Bash o bien desde una terminal de Linux hacemosng new nombre-de-tu-appcd nombre-de-tu-appng serve -open # o bien, la versin corta es ng s -oCorrer los tests de un proyectoPara ejecutar los tests de un proyecto, te posicions en el directorio raz y ejecuts desde la consolang testArchivo de configuracin para Visual Studio CodeTe recomendamos que dentro del proyecto crees una carpeta .vscode y dentro un archivo settings.json que tenga este contenido:{ "[javascript]": { "editor.defaultFormatter": "rvest.vs-code-prettier-eslint", "editor.formatOnPaste": false, // required "editor.formatOnType": false, // required "editor.formatOnSave": true, // optional "editor.formatOnSaveMode": "file", // required to format on save }, "[typescript]": { "editor.defaultFormatter": "rvest.vs-code-prettier-eslint", "editor.formatOnPaste": false, // required "editor.formatOnType": false, // required "editor.formatOnSave": true, // optional "editor.formatOnSaveMode": "file", // required to format on save }, "[json]": { "editor.defaultFormatter": "rvest.vs-code-prettier-eslint", "editor.formatOnPaste": false, // required "editor.formatOnType": false, // required "editor.formatOnSave": true, // optional "editor.formatOnSaveMode": "file", // required to format on save }, "editor.codeActionsOnSave": { "source.fixAll": true }}Cambios al package.jsonDentro del archivo package.json del raz de tu proyecto debs tener estos scripts: "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "watch": "ng build --watch --configuration development", "test": "ng test", "lint": "eslint &#92;"**/*.{ts,tsx}&#92;" ", "lint:fix": "eslint --fix &#92;"**/*.{ts,tsx}&#92;" ", "build:prod": "ng build --prod", "test:prod": "ng test --browsers=ChromeHeadless --watch=false --code-coverage" },Agregando DependenciasInstalaremos algunas dependencias adicionales:# Installar ESLintnpm install --save-dev eslint @typescript-eslint/parser# Instalar plugins adicionalesnpm install --save-dev @typescript-eslint/eslint-plugin eslint-plugin-prettier# Instalar Prettier y sus dependenciasnpm install --save-dev prettier prettier-eslint eslint-config-prettierArchivo .nvmrcTener un archivo .nvmrc es conveniente si todo el equipo trabaja con NVM (el versionador de Node). El contenido especifica qu versin de Node vamos a utilizar:20.4.0Ejemplo de .gitignoreTe recomendamos que configures tu archivo .gitignore de la siguiente manera:# See http://help.github.com/ignore-files/ for more about ignoring files.# compiled output/dist/tmp/out-tsc# Only exists if Bazel was run/bazel-out# dependencies/node_modules# profiling fileschrome-profiler-events*.json# IDEs and editors/.idea.project.classpath.c9/*.launch.settings/*.sublime-workspace# IDE - VSCode.vscode/*!.vscode/settings.json!.vscode/tasks.json!.vscode/launch.json!.vscode/extensions.json.history/*# misc/.sass-cache/connect.lock/coverage/libpeerconnection.lognpm-debug.logyarn-error.logtestem.log/typings# System Files.DS_StoreThumbs.db# Angular cache.angularConfiguracin del linterEl linter es el proceso que genera advertencias o errores en base a la sintaxis y semntica de nuestros componentes. Lo interesante es que podemos configurar, por ejemplo, que escribir console.log o debugger no es cdigo que queremos que est en el ambiente productivo, pero s podramos admitirlo en desarrollo. Tambin se puede configurar validaciones como el uso de let en lugar de const, variables sin utilizar, etc. Te dejamos la configuracin recomendada en el archivo .eslintrc.json que debe estar en el directorio raz:{ "parser": "@typescript-eslint/parser", "extends": [ "plugin:@typescript-eslint/recommended" ], "parserOptions": { "ecmaVersion": 2021, "sourceType": "module" }, "rules": { "semi": [ 2, "never" ], "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/explicit-module-boundary-types": ["off"], "@typescript-eslint/no-var-requires": "off" }}Para ejecutar el linter desde la lnea de comandos, pods escribirnpm run lintcon el archivo package.json que contenga los scripts que arriba te dejamos. Es importante hacerlo ya que el CI de Github Actions lo va a ejecutar para pasar el build, para arreglar automticamente todos los problemas que detecta el linter pods hacernpm run lint:fixConfiguracin del archivo de testAl archivo karma.conf.js que est en el directorio raz hay que agregarle la opcin para que genere el porcentaje de cobertura en formato json tambin: coverageReporter: { dir: require('path').join(__dirname, './coverage/eg-conversor-angular'), subdir: '.', reporters: [ { type: 'html' }, { type: 'text-summary' }, // &lt;-- agregar una coma al final { type: 'json-summary' } // &lt;-- agregar esta lnea ] }, Si no tens un archivo karma.conf.js lo pods generar desde el Angular CLI: ng generate config karmaOtros archivos tilesEn la carpeta raz cre los siguientes archivos .htmlhintrc (configuracin del Linter para HTML), con el siguiente contenido{ "tagname-lowercase": false, "attr-lowercase": false, "attr-value-double-quotes": true, "doctype-first": false, "tag-pair": true, "spec-char-escape": true, "id-unique": true, "src-not-empty": true, "attr-no-duplication": true, "title-require": true} .prettierrc.json (configuracin de Prettier para eliminar puntos y coma, definir tab de 2 espacios, utilizar single quote, etc.) Es importante que tod@s tengan esta configuracin para que no haya un montn de conflictos en git a la hora de pushear.{ "singleQuote": true, "trailingComma": "none", "endOfLine": "auto", "tabWidth": 2, "semi": false}Ajustes para el % de coberturaPara tener informacin ms precisa sobre el porcentaje de cobertura de tus tests, en el archivo app.component.spec.ts de tu directorio src/app tens que agregar este import:import './app.module'Ejemplo de un archivo para Github ActionsPara agregar el coverage tens que reemplazar XXXXXXXXX por el nombre de la carpeta donde est tu proyecto.Te dejamos este archivo de ejemplo que tens que guardar en .github/workflows/build.yml. Descargalo y reemplaz XXXXXXXXX por el nombre de la carpeta donde est tu proyecto.Cmo configurar los badges en tu README Para agregar el badge del build de Github Actions, segu estas instrucciones Para agregar el badge del porcentaje de cobertura, tens que agregar la imagen que genera el mismo build de Github Actions (reemplazando XXXXXXX por el nombre de la carpeta donde est tu proyecto): ![Coverage](./badges/XXXXXXX/coverage.svg)" + +} , + +{ + +"title" : "Aplicacion parcial", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/aplicacion-parcial.html", +"date" : "", +"content" : "Por aplicacin parcial se entiende a la aplicacin de una funcin, pero suministrando menos parmetros que los que esta requiere. El resultado de aplicar parcialmente una funcin es otra funcin que espera menos parmetros que la original, ya que puede realizar reemplazos en su definicin por expresiones o valores concretos. La aplicacin parcial es muy til para componer funciones y para parametrizar funciones de Orden Superior.Por ejemplo, las siguientes expresiones presentan aplicacin parcial: take 3 (+1) max "hola"Para visualizar mejor la transformacin que ocurre al aplicar parcialmente una funcin pueden consultar el tipo de las funciones sin aplicar y parcialmente aplicadas usando :t en el editor de Haskell. Podemos realizar un anlisis en funcin del tipo de las expresiones anteriores, cuantos ms parmetros se aplican menor aridad (cantidad de parmetros) tiene la funcin resultante:*Main&gt;:ttaketake:: Int -&gt; [a] -&gt; [a]*Main&gt;:ttake 3take 3 :: [a] -&gt; [a]*Main&gt;:t(+)(+)::Numa=&gt;a-&gt;a-&gt;a*Main&gt;:t(+1)(+1)::Numa=&gt;a-&gt;a*Main&gt;:tmaxmax :: Ord a =&gt; a -&gt; a -&gt; a*Main&gt;:tmax "hola"max "hola" :: [Char] -&gt; [Char]En el caso de max hola vemos tambin que no slo disminuy la cantidad de parmetros, sino que el tipo de la funcin resultante es ms particular, ya que hola obliga a que el otro valor esperado por el max tambin sea de tipo String para poder compararlos y determinar cul es mayor en orden alfabtico.Las siguientes funciones no estn aplicadas parcialmente: take (no est aplicada) odd (no est aplicada) odd 3 (est completamente aplicada, esta expresin no es de tipo funcin sino que es un booleano) max 0 3 (est completamente aplicada, esta expresin no es de tipo funcin sino que es un nmero)Una consecuencia de esto es que slo pueden aplicarse parcialmente funciones de 2 o ms argumentos. Para que la aplicacin parcial exista, es necesario que las funciones estn currificadas (ver Currificacin).Puedo aplicar parcialmente el segundo parmetro en vez del primero?En ocasiones sucede que no podemos aplicar parcialmente una funcin ya que el valor que le queremos pasar no es el primero que espera sino otro, por ejemplo si quiero saber si un nombre es extico, que se cumple si tiene x, k, q o w, no sera correcto intentar hacer:esExoticonombre=any(elem"XKQWxkqw")nombreYa que xkqw que es la lista en la cual quiero verificar si se encuentra uno de los caracteres del nombre, no es correcto tratar de aplicrselo a elem porque debera ser el segundo parmetro, no el primero. De hecho esa funcin va a compilar correctamente, pero no va a funcionar como esperamos, ya que al intentar usarla de esta forma:&gt;esExotico"Xiomara"Nosotros esperaramos que nos diga True, pero vamos a tener un error de tipos:Couldn'tmatchexpectedtype`[[Char]]'withactualtype`Char'Esto sucede porque si a elem le aplicamos un String (equivalente a [Char]), el resultado va a ser una funcin de tipo [ [Char] ] -&gt; BoolFormas posibles de resolverlo:Usando una expresin lambdaesExoticonombre=any(&#92;letra-&gt;elemletra"XKQWxkqw")nombreUsando notacin infija (como los operadores) en vez de prefija: En ocasiones nos parece ms natural usar las funciones de dos argumentos de forma infija, por ejemplo:&gt;10`mod`2Podemos aprovechar ese feature para aplicar el segundo parmetro y no el primero como hacemos con los operadores, por ej. (/2)esExoticonombre=any(`elem`"XKQWxkqw")nombreUsando la funcin flipEn Haskell existe una funcin de Orden Superior llamada flip cuyo tipo es (a -&gt; b -&gt; c) -&gt; b -&gt; a -&gt; c, y sirve justamente para resolver esta clase de problemas ya que lo que hace es aplicar la funcin que recibe con los parmetros en el orden inverso al que le llegan. Podramos usar flip parcialmente aplicada para lograr nuestro objetivo.esExoticonombre=any(flipelem"XKQWxkqw")nombreEjemplos de aplicacin parcialUsoSuponiendo que se tiene una funcin genrica como el between, genrica porque tiene bocha de parmetros:between menor mayor nro = menor &lt;= nro &amp;&amp; nro &lt;= mayorY se usa as:&gt; between 5 10 7TruePods hacer nuevas funciones a partir de esa, aplicando parcialmente.Por ejemplo, pods hacer una funcin ms especfica, que tome, en vez de tres cosas, slo una:(between 18 65)Porque le falta un parmetro!Y se puede usar para componer:debeVotar persona = (between 18 65 . edad) personaEjemploSupongamos que trabajamos para Spotify. Recin estamos empezando, y tenemos que modelar las canciones y los usuarios en Haskell.Elegimos modelarlos con data, donde cada cancin tiene un nombre, la cantidad de likes y dislikes; y cada usuario tiene un nombre de usuario y un nmero que representa hace cuntos aos usa Spotify:data Cancion = UnaCancion String Float Floatdata Usuario = UnUsuario String FloatPara decidir si poner una cancin en la pantalla de inicio de un usuario, el Sr. Spotify nos comenta que usan un algoritmo muy raro, con un clculo llamado tasaDeRecomendabilidad, que depende tanto de la cancin como del usuario; y ponen una cancin en la pantalla de inicio de alguien si esa tasa da mayor a 1000. El clculo de la tasaDeRecomendabilidad es una formulita que nos dan ellos, y nos dicen que se calcula as:tasaDeRecomendabilidad (UnUsuario _ antiguedad) (UnaCancion _ likes dislikes) = likes / dislikes * antiguedad + likes * pi / 29Notar que el clculo es ridculamente extrao (pero nosotros nos abstraemos de l). Y deciden si la tasa pasa su evaluacin as:esTasaRecomendable tasa = tasa &gt; 1000Nos delegan escribir cmo decidir si una cancin se pone en la pantalla de inicio de un usuario. Entonces hacemos:vaEnPantallaDeInicioDe usuario cancion = (esTasaRecomendable.tasaDeRecomendabilidad usuario) cancionAc, tasaDeRecomendabilidad es una funcin de 2 parmetros, pero como ya le pasamos uno, tasaDeRecomendabilidad usuario es una funcin de 1 parmetro. Porque ahora slo espera 1 parmetro, no 2 (el primero ya lo tiene)." + +} , + +{ + +"title" : "Aplicacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/aplicacion.html", +"date" : "", +"content" : "Cuando se aplica una funcin a unos argumentos, el resultado se obtiene sustituyendo esos argumentos en el cuerpo de la funcin respetando el nombre que se les dio a cada uno. Es posible que esto produzca un resultado que no puede ser simplificado (e.g. un nmero); pero es ms comn que el resultado de esa sustitucin sea otra expresin que contenga otra aplicacin de funciones, entonces se vuelve a hacer el mismo proceso hasta producir un resultado que no pueda ser simplificado (un resultado final).Por ej., siendo doble:doblex=x+xEl resultado de aplicar doble 3 (o sea, la funcin doble aplicada al nmero 3) se puede obtener de la siguiente manera:doble3={aplicamoslafuncindoble}3+3={aplicamoslafuncin+}6Si queremos obtener el resultado de doble (doble 2) en donde la funcin doble es aplicada 2 veces, podemos hacer:doble(doble2)={aplicamoslafuncindoblequeestdentrodelparntesis}doble(2+2)={aplicamoslafuncin+}doble4={aplicamoslafuncindoble}4+4={aplicamoslafuncin+}8Tambin podemos obtener el mismo resultado aplicando primero la funcin doble de ms afuera:doble(doble2)={aplicamoslafuncindoblequeestafueradelparntesis}doble2+doble2={aplicamoslaprimerfuncindoble}(2+2)+doble2={aplicamoslaprimerfuncin+}4+doble2={aplicamoslafuncindoble}4+(2+2)={aplicamoslasegundafuncin+}4+4={aplicamoslafuncin+}8El orden en que realicemos las reducciones (basta de decirle simplificar) no afecta al resultado final pero s a la eficiencia. Lo copado es que hay un motor que se encarga de esto (se llama motor de reducciones CUAC!). Para entender un poco ms lo que pasa detrs de escenas hace falta meterse en la estrategia de evaluacin usada por el motor.Aplicacin de funciones en HaskellNotacion matemticaf(a,b)+cdEn Haskellfab+c*d La aplicacin se denota solo poniendo espacio entre la funcin y sus argumentos. Adems, la aplicacin de funciones que no son operadores tiene una precedencia mayor que la de los operadores (un operador es una funcin que recibe 2 parmetros y se usa de forma infija ya sea un chirimbolo o una funcin con `)Las siguientes definiciones son equivalentes, podemos ver la precedencia para la aplicacin de div de forma infija y prefija:promedions=(sumns)`div`(lengthns)promedio'ns=sumns`div`lengthnspromedio''ns=div(sumns)(lengthns)" + +} , + +{ + +"title" : "Append como foldr f a", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/append-como--foldr-f-a-.html", +"date" : "", +"content" : "El desafoSe trata de escribir la funcin append en Haskell a partir de la funcin foldr. Hay tres versiones: append = expresion donde en la expresin dice foldr en algn lado, y realmente se usa. Se puede hacer usando nicamente tres funciones, foldr y dos ms. append = foldr f a donde f puede ser una expresin lambda append = foldr f a donde f no puede ser una expresin lambda Solucionesby Nicols Perez Santoro (lo que sigue a continuacin es una transcripcin del proceso mental en base al cual llegu a las soluciones).Primeroappend::[a]-&gt;[a]-&gt;[a]foldr::(a-&gt;b-&gt;b)-&gt;b-&gt;[a]-&gt;bSi defino append = foldr f, si tengo la lista [1,2,3] `append` [4,5,6] el foldr f me va a hacer4`f`(5`f`(6`f`[1,2,3]))Pero si pudiera hacer un flip de los argumentos, sera1`f`(2`f`(3`f`[4,5,6]))Entonces la primer versin del append esappend=flip(foldr(:))SegundoLa segunda versin tiene la formaappend=foldrfaPero miro el tipo de foldrfoldr::(a-&gt;b-&gt;b)-&gt;b-&gt;[a]-&gt;bOkay, y el tipo de foldr f a ?foldrfa::[a]-&gt;bPero yo quiero que foldr f a :: [a] -&gt; [a] -&gt; [a], que es el tipo de append. entonces b es ([a]-&gt;[a]). Entonces foldr en este caso queda instanciado asfoldr::(a-&gt;([a]-&gt;[a])-&gt;([a]-&gt;[a]))-&gt;([a]-&gt;[a])-&gt;[a]-&gt;([a]-&gt;[a])Es bastante largo eso. En fin, quiero que foldr, a partir del valor inicial, que va a ser una funcion, y la primer lista me devuelva una funcin que dada la segunda lista del append, me de la concatenacion de las listas. complicado. Pero pienso, si la lista de la izquierda est vaca, entonces foldr me tiene que devolver la funcin id. entonces digoappend2=foldrfidPero que es f? tiene que ser una funcin que dado un elemento y una funcion que dada una lista devuelve otra lista, devuelva otra funcion que dada una lista devuelva la lista que devolvera la funcin esta, pero con el elemento al principio.f::a-&gt;([a]-&gt;[a])-&gt;([a]-&gt;[a])feg=&#92;l-&gt;e:glY esta es la segunda versin. Un tanto complicaditoTerceroLa tercer versin claramente tiene que ser como la segunda, pero sin lambda expresions .!!! Si reduzco un poco, llego a estof'e=(.)(e:)Donde(.)::([a]-&gt;[a])-&gt;([a]-&gt;[a])-&gt;([a]-&gt;[a])(e:)::([a]-&gt;[a])pero(:)::(a-&gt;[a]-&gt;[a])f'::([a]-&gt;[a])-&gt;([a]-&gt;[a])Los tipos me dicen que componga! pero como compongo?(:)::a-&gt;([a]-&gt;[a])(.)::([a]-&gt;[a])-&gt;([a]-&gt;[a])-&gt;([a]-&gt;[a])entonces(.).(:)::a-&gt;([a]-&gt;[a])-&gt;([a]-&gt;[a])entoncesappend3=foldr((.).(:))idMORALEJA:LOS TIPOS SON MIS AMIGOS. Guan todo el razonamiento" + +} , + +{ + +"title" : "Configuracion de arena", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/arena-configuracion.html", +"date" : "", +"content" : "Estructura de un proyecto ArenaEn general una aplicacin arena consta de dos componentes o partes: el dominio la vistaSi bien podemos tener todas las clases de ambas partes en un nico proyecto, lo ms prolijo es plasmar esa separacin en dos proyectos. Porque por ejemplo, para el TP podrn reutilizar el dominio entre las diferentes tecnologas.Dependencias de los proyectosEntonces en ese esquema si seguimos con la idea de que el dominio no debe estar acoplado a la tecnologa de la vista directamente, nuestro proyecto dominio no depender del artefacto arena, pero s de otro artefacto ms abstracto que establece contratos de los objetos de negocio: uqbar-domain.Por otro lado, nuestro proyecto que tendr la vista en arena s, lgicamente depender del artefacto arena.La siguiente figura resume esto:Nota: si hacemos un nico proyecto con dominio + ui arena, podemos slo depender de arena y transitivamente veramos a uqbar-domain.Lo que deben tener tus pom.xmlDependencias para proyectos de UI - XtendSi vas a definir tus objetos de dominio en un proyecto aparte (cosa que recomendamos) tens que definir esta dependencia&lt;dependency&gt; &lt;groupId&gt;org.uqbar-project&lt;/groupId&gt; &lt;artifactId&gt;uqbar-domain&lt;/artifactId&gt; &lt;version&gt;3.6.3&lt;/version&gt;&lt;/dependency&gt;Crear un proyecto de Arena en XtendSi ests trabajando Arena-UI desde xtend, esta configuracin contiene todas las dependencias que necesits (JUnit, el compilador Xtend, Arena UI, Uqbar Domain, etc.):&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt; &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt; &lt;artifactId&gt;****ACA PONES EL NOMBRE DE TU PROYECTO****&lt;/artifactId&gt; &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt; &lt;name&gt;****UNA VEZ MAS EL NOMBRE DE TU PROYECTO****&lt;/name&gt; &lt;description&gt;****DESCRIPCION DE TU PROYECTO****&lt;/description&gt; &lt;parent&gt; &lt;groupId&gt;org.uqbar-project&lt;/groupId&gt; &lt;artifactId&gt;arena-xtend-parent&lt;/artifactId&gt; &lt;version&gt;3.6.3&lt;/version&gt; &lt;/parent&gt; &lt;!-- Si tens dependencias con tu proyecto de dominio --&gt; &lt;dependencies&gt; &lt;dependency&gt; &lt;groupId&gt;GRUPO-PROYECTO-DE-DOMINIO&lt;/groupId&gt; &lt;artifactId&gt;NOMBRE-PROYECTO-DE-DOMINIO&lt;/artifactId&gt; &lt;version&gt;VERSION-ACTUAL-PROYECTO-DE-DOMINIO&lt;/version&gt; &lt;/dependency&gt; &lt;/dependencies&gt; &lt;!-- fin de dependencias con proyecto de dominio --&gt; &lt;repositories&gt; &lt;repository&gt; &lt;id&gt;uqbar-wiki.org-releases&lt;/id&gt; &lt;name&gt;uqbar-wiki.org-releases&lt;/name&gt; &lt;url&gt;http://maven.uqbar.org/releases&lt;/url&gt; &lt;/repository&gt; &lt;repository&gt; &lt;snapshots /&gt; &lt;id&gt;uqbar-wiki.org-snapshots&lt;/id&gt; &lt;name&gt;uqbar-wiki.org-snapshots&lt;/name&gt; &lt;url&gt;http://maven.uqbar.org/snapshots&lt;/url&gt; &lt;/repository&gt; &lt;/repositories&gt; &lt;build&gt; &lt;plugins&gt; &lt;plugin&gt; &lt;groupId&gt;org.eclipse.xtend&lt;/groupId&gt; &lt;artifactId&gt;xtend-maven-plugin&lt;/artifactId&gt; &lt;version&gt;2.19.0.M1&lt;/version&gt; &lt;/plugin&gt; &lt;plugin&gt; &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt; &lt;version&gt;3.5.1&lt;/version&gt; &lt;configuration&gt; &lt;source&gt;1.8&lt;/source&gt; &lt;target&gt;1.8&lt;/target&gt; &lt;/configuration&gt; &lt;/plugin&gt; &lt;/plugins&gt; &lt;/build&gt;&lt;/project&gt;Dependencias para proyectos de UI - JavaAgregar dos referencias en el pom al framework Arena (consideramos Arena = Arena-JFace como predeterminado) al proyecto de dominio (asumimos que vamos a tener dos proyectos separados, uno para el dominio y otro para la ui).Por ejemplo, las dependencias en nuestro pom podran quedar as:&lt;dependencies&gt; &lt;dependency&gt; &lt;groupId&gt;org.uqbar-project&lt;/groupId&gt; &lt;artifactId&gt;arena-jface&lt;/artifactId&gt; &lt;version&gt;3.6.3&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;uqbar-project.org&lt;/groupId&gt; &lt;artifactId&gt;videoclub-domain&lt;/artifactId&gt; &lt;version&gt;1.0.0-SNAPSHOT&lt;/version&gt; &lt;/dependency&gt;&lt;/dependencies&gt;Las otras dependencias como JUnit se toman de la definicin del parent project, en caso de ser necesario se debe agregar a mano:&lt;dependency&gt; &lt;groupId&gt;junit&lt;/groupId&gt; &lt;artifactId&gt;junit&lt;/artifactId&gt; &lt;version&gt;4.12&lt;/version&gt; &lt;scope&gt;test&lt;/scope&gt;&lt;/dependency&gt;Si no quers tocar el pom.xml a mano, pods agregarlo a travs del plugin M2clipse: botn derecho sobre el proyecto, Maven &gt; Add Dependency &gt; buscs arena y tiene que aparecer arena-jface, buscs la versin que quers (o si tens dudas la ltima) y acepts. Entonces el plugin va a descargarlo (si no lo tiene en tu repositorio local). Lo mismo con las dems dependencias que necesites.Configurar launcherEn Run &gt; Run Configurations &gt; Java Application &gt; New launch configuration (busc el botn de la toolbar que est a la izquierda) y en la solapa Arguments, tens que indicarle en VM Arguments que use el Launcher propio de Arena:-Djava.system.class.loader=org.uqbar.apo.APOClassLoaderde lo contrario te va a aparecer un mensaje de error:Exceptioninthread"main"java.lang.RuntimeException:EstaaplicacinnoestcorriendoconelClassLoadernecesario.CorralaaplicacinconelsiguienteparmetroparalaVM:-Djava.system.class.loader=org.uqbar.apo.APOClassLoader.ElClassLoaderactuales:sun.misc.Launcher$AppClassLoader@6fd3633catorg.uqbar.arena.Application.validateClassLoader(Application.java:32)atorg.uqbar.arena.Application.`&lt;init&gt;`(Application.java:24)En muchos ejemplos tenemos un archivo .launch que tiene esta configuracin ya cargada.TroubleshootingQu hacer cuando nos bajamos ejemplos (o desarrollamos uno nuevo) y no nos andan? Chequear esta listaMaven - versinRevis que Maven est correctamente instalado en tu mquina y que tens el settings.xml correctamente configurado. Cualquier duda fijate en el tutorial de instalacin de Maven.Tambin asegurate que la versin de Maven sea 3.0.x o posterior, o vas a tener un mensaje de error similar a ste:[INFO]UnabletoinitialiseextensionsComponentdescriptorrole:'com.jcraft.jsch.UIKeyboardInteractive',implementation:'org.apache.maven.wagon.providers.ssh.jsch.interactive.PrompterUIKeyboardInteractive',rolehint:'default'hasahint,butthereareotherimplementationsthatdon'tMaven - error de dependenciasMaven tiene un solo gran inconveniente: si al tratar de descargar una dependencia tens un problema de conexin, despus de una cierta cantidad de reintentos queda el archivo de la dependencia corrupto y tu entorno no va a funcionar. Las palabras que hay que buscar en la solapa Problems es resolution will not be reattempted until the update interval of central has elapsed or updates are forced.La solucin es ir a tu carpeta C:&#92;users&#92;tuUsuario&#92;.m2 (o ~/.m2 de Linux/Mac), verificar la carpeta del componente que te dice que no puede bajar, verificar que no hay un archivo .jar y borrar la carpeta padre. Por ejemplo, nos aparece este mensaje:CoreException: Could not get the value for parameter compilerId for plugin execution default-testCompile: PluginResolutionException: Plugin org.apache.maven.plugins:maven-compiler-plugin:3.5.1 or one of its dependencies could not be resolved:Failure to transfer org.codehaus.plexus:plexus-component-annotations:jar:1.5.5 from https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced.Original error: Could not transfer artifact org.codehaus.plexus:plexus-component-annotations:jar:1.5.5 from/to central (https://repo.maven.apache.org/maven2): The operation was cancelled. pom.xml /2 line 46 Maven Project Build Lifecycle Mapping ProblemEso est en la carpetaC:&#92;users&#92;tuUsuario&#92;.m2&#92; org&#92; codehaus&#92; plexus&#92; plexus-component-annotationsY adentro seguro que falta un jar, debe haber un archivo con extension .lastUpdated que indica el momento en el que intent bajarse la dependencia y fall. Lo mismo hay que hacer con cada uno de los componentes que marque el error.Borrar todos los hijos de .m2 es lo ms fcil, pero tambin les va a llevar infinito tiempo y si la conexin de Internet es mala, les puede volver a pasar el mismo error con distintos componentes. Moraleja: cuando uno se baja dependencias (con Maven o cualquier otra herramienta), hay que asegurarse de tener buena conexin de Internet.Source folders del proyectoLos source folders de los proyectos (que tienen maven como estructura central del proyecto) deben sersrc/main/java y src/test/java (para proyectos Xtend o Java)Si te aparece como source folder slo el src, o bien si no tens source folders: corr el plugin de maven: botn derecho sobre el proyecto &gt; Configure &gt; Maven project (o mvn compile) si el proyecto tiene la naturaleza Maven (aparece una M sobre el nodo del proyecto en el Project Explorer), prob hacer un Maven &gt; Update project revis si efectivamente tens una estructura de directorio src/main/lenguaje, en base al lenguaje que ests utilizando. Esa estructura debe respetarse. JDKRevis que tengas instalada una JDK (no JRE, tiene que ser JDK con las herramientas para desarrollar en Java como el compilador, debug, etc.) y que la versin de ese JDK sea 1.8 superior. Si quers usar una JDK 1.7 inferior te va a aparecer el siguiente mensaje de errorjava.lang.UnsupportedClassVersionError:---aplicacindeArena---:Unsupportedmajor.minorversion51.0porque Arena est compilado con una JDK 1.8Problemas para encontrar la ventana ejecutableSi te aparece un error similar a ste al correr un launcher:Error:nosehaencontradoocargadolaclaseprincipalorg.uqbar.arena.examples.conversor.xtend.ConversorWindowRevis si tens correctamente definidos los source folders (punto anterior): al abrir los archivos tiene que aparecer correctamente coloreado y sin errores de compilacin y si tens apuntado en tu proyecto un JDK vlido (que apunte a un directorio que exista en tu PC, revis Window &gt; Preferences &gt; Installed JREs)APOClassLoader not foundOtro problema que puede aparecer es:ErroroccurredduringinitializationofVMjava.lang.Error:java.lang.ClassNotFoundException:....APOClassLoaderentonces el problema puede darse porque no te descarg las dependencias de Maven correctamente. Revis los directorios de tu usuario/.m2/repository porque seguramente te falte bajar dependencias, pods probar haciendo Maven &gt; Update project (forzando el check Update snapshots), es poco probable que eso lo solucione pero al menos te puede ayudar a encontrar el origen de la dependencia errnea.Errores de launchersOtro problema que te puede ocurrir cuando corras un launcher que te descargaste de nuestros ejemplos es que te aparezca un error de este tipo:Launchconfigurationreferencesnon-existingprojectcelulares-ui-arena-scalaEn este caso el problema es que te descargaste el proyecto del repositorio utilizando otro nombre que el que originalmente definimos. Entonces fijate cul es el nombre del proyecto que est esperando y renombralo a ese, o bien entr por el men Run Configuration y apunt el launcher al proyecto que vos definiste. Otra opcin puede ser que no hayas ejecutado el comando mvn compile (Run As &gt; Maven build Goal compile)Links relacionados Temario Algoritmos III Instalacin de Arena" + +} , + +{ + +"title" : "Instalacion de arena", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/arena-instalacion.html", +"date" : "", +"content" : "Para instalar el entorno de Arena en Xtend Necesits una JDK (Java Development Kit) 1.8, no puede ser superior ya que no se lleva bien con el Class Loader de Arena. Recomendamos usar la ltima versin de Eclipse (2019-06) para Java (puede ser la versin anterior pero siempre es mejor trabajar con la ltima) con el plugin Xtend 2.18 (el Update Site es http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/) Y la ltima versin de Maven (no es tan importante que sea la ltima pero s que sea 1.3.x) Si ests trabajando en Windows, descargate el Git Bash El archivo .travis.yml te lo pods bajar de cualquiera de nuestros ejemplos, o generalo desde cero con este contenidodist: trustylanguage: javajdk: - oraclejdk8Links relacionados Temario Algoritmos III Configuracin de Arena" + +} , + +{ + +"title" : "Aritmetica en prolog", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/aritmetica-en-prolog.html", +"date" : "", +"content" : "El predicado isEn Prolog no pasa como en Haskell que tengo funciones que me devuelven cosas, sino que tengo predicados que relacionan individuos Entonces qu sucede cuando quiero hacer cuentas? Si probamos esto en el intrprete de Prolog, que est pensado para evaluar predicados, vamos a ver que falla:?- 2+2.ERROR: Undefined procedure: (+)/2 (DWIM could not correct goal)Eso no es porque no sea posible sumar nmeros, sino que el + no es un predicado. De hecho, si probamos esto otro, s funciona:?- 2+2 &gt; 1.YesEso demuestra que la suma anda, y que el predicado (&gt;)/2 se encarg de reducir esa expresin y compararla con el 1, lo cual dio un resultado booleano como hubiramos esperado.Y como me puedo saber cul es el resultado de una cuenta? O si una cuenta da un determinado resultado?Bueno, para esos casos, existe el predicado is, que es un predicado de aridad 2 que se puede escribir de forma infija. Al ser un predicado, sabemos que podemos hacer consultas individuales como la siguiente, para saber si es cierto que se verifica que una cuenta da un determinado resultado:?-5is2+3.YesPero ojo, la cuenta slo puede ir a la derecha:?- 4 + 1 is 2 + 3.No.A la derecha del is se escribe una operacin aritmtica. A la izquierda del is se escribe el resultado de esa operacin aritmtica.Luego podemos ver qu tan inversible es para determinar qu otros usos se le puede dar. El is slo es inversible por el primer parmetroEsto funciona:?-Xis6/2.X=3Pero esto no:?- 3 is X / 2.ERROR: is/2: Arguments are not sufficiently instantiatedErrores comunes con el isAc vienen una serie de warnings que deben tener MUY en cuenta:Error: usar = en vez de isUsar = para resolver operaciones aritmticas no es correcto. Por qu no se puede usar = para aritmtica? Veamos un ejemplo:?-3+5=2+6.No?-3+5=5+3.No?-3+5=8.NoEl muy simptico slo nos va a decir true cuando las dos expresiones de ambos lados del igual sean idnticas, no va a intentar resolver la igualdad:?-3+5=3+5.YesMuy til, no? :PEn general en la materia no vamos a usar el = ya que preferimos el uso de pattern matching y consultas individuales cuando eso nos sirva para resolver el problema que tenemos.Error: tratar de acumularComo ya saben, en lgico no hay asignacin sino unificacin; una vez que las variables se ligan, permanecen ligadas hasta que termine la consulta, por ende no hay que pensar al is como un mecanismo para asignar. Es decir, no vale preguntar algo como:?-edad(pepe,E),EisE+1.NoNo existe ningn nmero E que sea igual a E + 1. Supongamos que la edad de pepe era 15, el motivo por el cual es falso es porque 15 no es 16. Bsicamente lo que estara pasando es esto:?-15is15+1.NoError: Usar is para verificar igualdad de valoresEl is es slo para operaciones aritmticas. Si bien funciona, lo siguiente es un error conceptual:edad(juan,Edad):- Edadis10.La manera correcta de hacerlo es aprovechando que al hacer pattern matching, prolog verifica que el valor sea ese, sin usar el igual el is:edad(juan,10).Y listo!Ver Sobre el uso del igual en Prolog para ms informacin.Error: Usar is para igualar variablesEsto es el mismo caso que el error anterior. El is es slo para operaciones aritmticas. Si bien funciona, lo siguiente es un error conceptual:mismaEdad(PersonaA,PersonaB):- edad(PersonaA,EdadA), edad(PersonaB,EdadB), EdadAisEdadBLo mismo sucede aqu:mismaEdad(PersonaA,PersonaB):- edad(PersonaA,EdadA), edad(PersonaB,EdadB), EdadA=EdadBLa manera correcta de hacerlo es:mismaEdad(PersonaA,PersonaB):- edad(PersonaA,Edad), edad(PersonaB,Edad).Porque si dos individuos deben ser el mismo, entonces alcanza con escribirlos con la misma variable, no como otra condicin. De esta forma estamos haciendo una consulta existencial respecto a la edad de la PersonaA y luego una consulta individual para validar si es cierto que la edad de PersonaB es esa que ya conocemos. Vemos que de sta manera mejoramos la declaratividad (leo qu es lo que quiero, y hay menos detalles algortmicos: si la edad es la misma lo escribo igual y listo). El motor de Prolog se encarga del resto.Ver Sobre el uso del igual en Prolog para ms informacin.Error: Usar is para resolver ecuacionesComo dijimos arriba, el predicado is/2 no es completamente inversible, es inversible solo para el primer argumento, lo que va a la izquierda. O sea, no vale preguntar:?-3isX+1.ERROR: is/2: Arguments are not sufficiently instantiatedPorque el motor de Prolog no sabe resolver ecuaciones. En ste caso, el error dir algo como Arguments are not sufficiently instantiated, lo cual es otra manera de decir No soy inversible a derecha, slo me pods poner algo sin unificar a izquierda" + +} , + +{ + +"title" : "Arquitecturas", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/arquitecturas.html", +"date" : "", +"content" : "Un artculo interesante de fowler: http://martinfowler.com/bliki/DatabaseThaw.htmlClasificacin general de las partes de una aplicacinNormalmente uno habla de tres capas, pero hay distintas formas de dividir y las divisiones principales son 4 que las gente agrupa de una u otra manera segn distintas escuelas:PresentacinPersistenciaDominioAplicacinTransformacin de los datos de entrada para hacerlos llegar hasta el dominioQue la presentacin no conozca al dominioQue el dominio no conozca a la presentacinHay un lugar intermedio de almacenamiento:Wrapper del requestVolcar los datos del request en un mapaVolcar los datos en un dto (bean)Estructura oficial de una aplicacin El struts llena un bean o mapa. El controller (action de struts) recibe ese bean, invoca a un servicio. El servicio es la fachada de la aplicacin (facade) y esconde y proteje a los objetos de negocio*Permitetenermuchasinterfacesdeusuariosobreelmismodominio*Permiteinterponercomportamientogenricocomomanejodetransaccionesyseguridadyremoticidad.*Manejalapersistencia*Proveeunainterfazsimplificadadelaaplicacin*Decidequ"casosdeuso"publicaryqucosasno" + +} , + +{ + +"title" : "Arrays literales en smalltalk", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/arrays-literales-en-smalltalk.html", +"date" : "", +"content" : "Por si les sirve les comento un toque como funciona el tema de los arrays en smalltalk.Acurdense que en Smalltalk vale usar arrays literales.Array: coleccin de tamao fijo.Literal: objetos especiales como nmeros, caracteres, strings, nil, booleanos, arrays literales (cuac), etc.Para usar un Array literal los elementos del array deben ser literales, ejemplos:#('brujula''mapa''botellaDeGrogXD')Escribir eso, genera un array que tiene 3 strings, si necesitan un Bag pueden escribir#('brujula''mapa''botellaDeGrogXD')asBagEl tema est cuando queremos un array que tiene objetos que deben obtenerse a travs de mensajes, ejemplo:#(4+3)Uno ingenuamente se pensara que eso da un array de un elemento (el objeto 7), pero Smalltalk piensa que quisimos hacer un array que tiene 3 elementos (el 4, el smbolo +, y el 3)Para crear arrays con objetos que no son literales, se deben utilizar arrays dinmicos (en vez de escribir #() se escribe { }, en vez de separarse los elementos con espacio se separan con punto){4+3}"Estoesunarrayconunsoloelemento,elnmero7"{4+3.'hola'size.Datetodayyear}"Estoesunarraycontreselementos:7,4y2011"De todas formas, en los parciales no suele ser habitual el uso de Arrays (ya que queremos colecciones con tamao variable y los elementos que componen dicha coleccin son desconocidos al escribir el cdigo)." + +} , + +{ + +"title" : "wiki.template landing page", +"category" : "", +"tags" : "", +"url" : "/articles.html", +"date" : "", +"content" : "Articulos de la wiki FAQ Abstraccion Temario de Algoritmos II Temario de Algoritmos III Amigandonos con el entorno de desarrollo Android - cmo cambiar cono y ttulo de la app Ciclo de vida de una actividad en Android Preparacion de un entorno de desarrollo android Introduccin al desarrollo con Android Instalacion de Entorno Angular Aplicacion parcial Aplicacion Append como foldr f a Configuracion de arena Instalacion de arena Aritmetica en prolog Arquitecturas Arrays literales en smalltalk Ast abstract syntax tree Atributos de calidad Backtracking Bagna cauda Bajar un proyecto maven de un repositorio git Bibliografia sobre programacion avanzada orientada a objetos Binding polimorfismo y sobrecarga Bloques Brownies C ++ C Calculo del tipo de una funcion en haskell Calidad de las pruebas unitarias Cannot construct the infinite type Cantidad de parametros de una funcion en haskell Ciclo de vida de un objeto Clase abstracta vs interfaces Clase abstracta vs interfaz Clases anonimas en java Clases vs instancias Clases Coeficiente de felicidad docente Comidas Como bajar y correr un ejemplo en wicket Como crear una subclase en squeak Como contribuir a la wiki Como hacer para que de un objeto muestre lo que yo quiero Como hacer predicados de orden superior Composicion oop Composicion Comunicacion Concepto de funcion Conceptos basicos del diseno Conceptos de ingenieria de software y de sistemas Configuracion de maven para poder utilizar las herramientas de uqbar Configuraciones generales para cualquier eclipse Conocimiento de dominio y refactoring Creacion de objetos con parametros Creacion de un proyecto maven basico Crear un proyecto en xp dev Css cual es la diferencia entre una tupla y una lista Cuando usar parentesis Cuestiones basicas para resolver el parcial de objetos Currificacion Data definiendo nuestros tipos en haskell Declaratividad vs expresividad Declaratividad Definiciones locales where Deploy en maven central Deploy componentes Uqbar Desafio Construir esta sucesin Desafio find con notacion point free Desafio hacer que un data propio sea enum Desafio ordenar con rbol B Desafio pirmide de nmeros Desafio suma de distancias Desafio Suma Par Desafio triada uqbariana Desafios cafe con leche Design temario Diagrama de clases Diccionarios Diferencia entre objetos y procedural con un ejercicio de la guia 1 Diferencias entre polimorfismo abstraccion y encapsulamiento Diseno iterativo Diseno y sistemas de tipos Diseno y tecnologia Paradigma logico, Predicado distinct Dont Cross the Beams by Kent Beck Double dispatch Dsl Efectos y diseno El papel del diseno en la metodologia de desarrollo Uso del signo pesos ($) en haskell Elementos teoricos para comparar tecnologias de presentacion Encapsulamiento Entradas al proceso de diseno Errores comunes usar un predicado como si fuera una variable Errores comunes al comenzar a trabajar con haskell Errores comunes con select y collect Errores comunes Errores en haskell Errores frecuentes al programar en logico Escribiendo un paper Esquemas de tipado Estado identidad y diseno Estado y diseno Estereotipos de objetos Estrategias de evaluacion Evaluacion diferida y diseno Excepciones - Resumen avanzado Excepciones Expresiones lambda Expresividad Fideos Flattening vs linearization Fold Formato de un paper Frases teadepeanas Funciones por partes Function object Garbage collector Git un versionador distribuido Introduccin a Gradle Groovy vs scala Guia de instalacion de maven Guia de instalacion de rails Guia de instalacion de ruby Guiso de Lentejas Herencia Herramientas de desarrollo con android Herramientas de instanciacin Herramientas utiles Orden superior y calculo variacional (Referencia Externa) Home Html Hugs trex insertfield not in scope Igualdad vs. Identidad Inferencia de tipos Inject into Inmutabilidad Intro a colecciones Introduccion a las metodologias de desarrollo de software Java Javascript JDK vs. JRE json Juegos de estrategia Testeo unitario avanzado Kotlin - control de versiones Bajar un proyecto Kotlin - Gradle de un repositorio git Integracin continua para materias con Kotlin Kotlin - Cmo generar un proyecto desde cero Guia rapida de Kotlin Kotlin - Preparacion del entorno de desarrollo Kotlin - pagina principal Lambdas en java 8 Lectura de un paper Lenguajes del paradigma logico Lenguajes especificos de dominio Lenguajes para centrales nucleares Lenguajes Ley de demeter Libreria y framework Lista de proyectos Listas por comprension Locro Logico trabajo con valores Lombardizacion Macros en Scala Manejo de booleanos en haskell Manejo de booleanos en smalltalk Manejo de booleanos Manejo de errores Manejo de memoria en c Maquina virtual Masa de pizza Introduccin a Maven Mejorar la experiencia del pharoer Mensajes de colecciones Mensajes y metodos Metamodelo Metaprogramacion Method lookup Method missing Metodos de clase para crear objetos inicializados Min y max Mixins Modelando objetos responsabilidades y delegacion Monada No hay instancias para el Show Nombres de clases Normalizacion en objetos Notacion point free Manejo de dependencias con NPM Objective c Observer en pharo smalltalk Objetos factory - instanciando objetos Temporary variables Orden superior y diseno Orden superior Otros temas interesantes de programacion Pagina principal Palitos de queso Panqueques Paradigma de objetos method lookup Paradigma de objetos Paradigma de programacion Paradigma funcional Paradigma logico casos de no inversibilidad Paradigma logico como pienso la resolucion de un punto Paradigma logico conjuncion y disyuncion Paradigma logico detalles del swi prolog Paradigma logico el forall Paradigma logico existe vs para todo Paradigma logico forall no siempre con member Paradigma logico functores Paradigma logico generacion Paradigma logico individuos compuestos Paradigma logico individuos simples Paradigma logico introduccion Paradigma logico inversibilidad Paradigma logico listas Paradigma logico multiples respuestas Paradigma logico negacion Paradigma logico un poco de nomenclatura Paradigma logico Paradigmas de programacion Parsers monadicos Patrones de comunicacion entre componentes Pattern matching polimorfismo y diseno Pattern matching en haskell Pepita Pharo para programadores ozonosos Script mapeo manual Objetos / Relacional Script temario MongoDB Programacion con herramientas modernas Polimorfismo en el paradigma de objetos Polimorfismo en el paradigma logico Polimorfismo parametrico y ad hoc Polimorfismo Portal del investigador Possibly incorrect indentation or mismatched brackets Precedencia de los operadores mas comunes en haskell Precedencia de mensajes Preguntas frecuentes del paradigma logico Preguntas frecuentes Preparacion de un entorno de desarrollo groovy Preparacion de un entorno de desarrollo java 8 Preparacion de un entorno de desarrollo java Preparacion de un entorno de desarrollo scala Problemas comunes con los tipos numericos de haskell Prototipado vs clases Prototipado Pseudovariable Publicar un proyecto en svn Python que entendemos por programacion orientada a objetos Instalacion de ReactJS Recursividad en haskell Recursividad en logico Redefinicion Refactoring Reflection Relleno caprese Relleno dale Relleno de carne Representacion de informacion Resolver problemas de dependencias maven dentro de eclipse Responsiveness Resumen de wicket pros y contras Resumen de lenguajes basados en prototipos Robustez de los lenguajes Ruby Sabores de colecciones Salsa jack daniel s Scala Self pseudovariable Self Sintaxis de smalltalk Smalltalk Sobre el uso del igual en prolog Super Tecnicas avanzadas de programacion Template method Testeo unitario avanzado Testing Tipo abstracto de datos Tipos de haskell Tipos de mensajes en smalltalk Tips para aprobar un parcial de funcional Tips para concursos docentes Tips para la resolucion de un parcial de tadp Traits Transparencia referencial efecto de lado y asignacion destructiva Interfaces y union types en Typescript Tutorial de squeak y pharo Tutorial de squeak Tutoriales para desarrollo java Typeclasses Typedefs y tipos anonimos Integracion de la ui en una arquitectura de un sistema de software Clasificacion de las UI Definiciones iniciales de ui Elementos a tener en cuenta al programar ui Formas de vincular una vista con el modelo de dominio Intro a MVC Application model. Extendiendo el MVC. Navegacin Arena. Manejo de transacciones. Validaciones y manejo de errores en la UI Introduccin a la Arquitectura web unexpected Unificacion y pattern matching Uso de features de lenguajes dinamicos Value object Variables locales en metodos Variables y metodos de clase Variables Warning singleton variables Xtend - control de versiones Cmo generar un proyecto Xtend nuevo Guia rapida de Xtend Preparacion de un entorno de desarrollo xtend Xtend - pagina principal " + +} , + +{ + +"title" : "Ast abstract syntax tree", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ast-abstract-syntax-tree.html", +"date" : "", +"content" : "A esto hay que darle forma AST simplemente es un arbol que lo que hace es representar un programa (o parte de l), se organiza en nodos y puede haber nodos que contengan otros (nada loco).Lo interesante es usarlo, para armarlo ya est hecho, esta bueno aprender a usarlo Aka como obtenerlo, como visitarlo, que sabe hacer cada nodo, como agregarle comportamiento.Si abris Pharo vas a ver que los nodos son RBNode, ejemplo RBVariableNode, RBSequenceNode, RBMessageSendNode (...).Si queres ver como armas un AST de un cacho de codigo tenes RBParser parse: unString y te devuelve un nodo del ast (el parente, un program node si parseo bien).No encontre mucho que leer.. a ver vi una presentacion y lei algo a media que me paso ducasse, y despues para ver como se puede jugar con poder sobre el AST lei el paper de Helvetia y otro de SmallLint (este ultimo es bien concreto sobre reglas y transformaciones).Despues me puse a jugar y a reconocer nodos segun lo que esta seleccionado facil porque abri el AltBrowser que ya lo hacia.Despues nada browsear el codigo para entender un poco como se implementa si encontras algo mas organizado decime (en otro mail te reenvio lo que me mando ducasse para leer)Reng10aEmbeddingLanguages.pdfReng10bDomainSpecificProgramChecking.pdf" + +} , + +{ + +"title" : "Atributos de calidad", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/atributos-de-calidad.html", +"date" : "", +"content" : "Atributos de calidad (tambin cualidades del software) son caractersticas no funcionales que se consideran deseables en un sistema de software. Sin embargo, no todos los sistemas de software deben tener en cuenta todos estos atributos o cualidades, algunas sern ms importantes que otras dependiendo del sistema, y ciertamente no se pueden maximizar todas a la vez.Se establece una diferencia entre cualidades y requerimientos, porque algunas de ellas pueden incorporarse como entrada al diseo por un camino distinto al del anlisis (por ejemplo, como restricciones de arquitectura o influencias del entorno).SimplicidadSimplicidad es la ausencia de complejidad o dificultades. En el desarrollo de software puede resultar de interes diferenciar entre complejidades esenciales y accidentales. Complejidad esencial: las que son propias o intrnsecas al problema que se desea solucionar. Es natural que un problema complejo tenga soluciones con algn grado de complejidad. complejidades accidentales: aquellas que surgen por malas decisiones de diseo. Naturalmente, se intentar evitar disear soluciones que sean ms complejas de lo que el problema requiere.Determinar si una dificultad en un diseo o programa es esencial o accidental, nos permite atacar las dificultades accidentales, buscando soluciones ms simples.Correctitud, consistencia, completitudCorrectitud:Ausencia de errores.Consistencia:Coherencia entre las operaciones que realiza el usuario.Completitud:Capacidad del sistema para realizar todas las operaciones que usuario podra requerir.Un artculo interesante sobre correctitud consistencia y completitud: Worse is betterRobustezRobusto es un sistema que goza de buena salud y que brinda garantas de que va a continuar teniendo buena salud. Algunos sntomas de un sistema robusto son: la capacidad de ser modificado sin introducir errores (opuesto a error prone) durabilidad del sistema funcionando correctamente (no aparecen errores aleatorios)Diferentes usuarios tendrn diferentes visiones de la robustez del sistema.FlexibilidadTambin llamada modificabilidad, es la capacidad para admitir cambios que pueden ser necesarios tanto por un cambio de requerimientos como por la deteccin de un error que debe ser corregido. Una variante de flexibilidad es la extensibilidad, es decir, la posibilidad de agregar nuevos requerimientos.PerformanceLa performance es una medida de la eficiencia en el uso de recursos del sistema ejecutndose, por ejemplo: Uso de procesador Memoria Almacenamiento permanente (discos rgidos, etc). Uso de redes o cualquier otro recurso fsico.EscalabilidadEs la capacidad de un sistema para trabajar con diferentes cantidades de trabajo, como cambios en el volumen de datos o flujo de pedidos. Con frecuencia se estudia la escalabilidad de un sistema hacia arriba, es decir, se mide la capacidad del sistema para manejar, por ejemplo, un mayor volumen de datos. La medida de escalabilidad no requiere que el sistema funcione intacto en las nuevas condiciones, en cambio es una medida de la facilidad con la que se lo puede adaptar al nuevo entorno, por ejemplo, si est preparado para que yo agregue un servidor ms a un cluster eso se podra considerar escalable.Tambin puede ser de utilidad analizar la flexibilidad hacia abajo, es decir, la posibilidad de un sistema de adaptarse a un entorno ms sencillo. En estos casos, se analiza, por ejemplo, la posibilidad de evitar el uso de recursos que encarecen el sistema y podran no ser indispensables, por ejemplo ejecutar toda la aplicacin en un nico servidor en lugar de cada capa en uno distinto o bien reemplazar determinados componentes adquiridos por otros de menor costo de licencia.Un error comn es confundir escalabilidad con extensibilidad.SeguridadAlgunas visiones de la seguridad son: Comprobar la identidad de las personas que intentan acceder al sistema. Garantizar que slo las personas especficamente autorizadas pueden ver determinada porcin de la informacin del sistema Garantizar que slo las personas especficamente autorizadas pueden modificar determinada porci de la informacin del sistema o bien realizar determinadas acciones.UsabilidadLa facilidad con la que el sistema o componente se puede utilizar o bien aprender a utilizar.ConstructibilidadLa constructibilidad es una medida inversa a la complejidad de la construccin del sistema. Las decisiones de diseo pueden afectar severamente la dificultad para construir ese sistema." + +} , + +{ + +"title" : "Backtracking", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/backtracking.html", +"date" : "", +"content" : "En un programa desarrollado usando el paradigma lgico, existe un motor que acta como control de secuencia para separar el algoritmo de bsqueda de soluciones del conocimiento de cada programa.Durante la ejecucin de un programa va evaluando y combinando las reglas lgicas de la base de conocimiento para lograr los resultados esperados. La implementacin del mecanismo de evaluacin puede ser diferente en cada lenguaje del paradigma, pero en todos los casos debe garantizar que se agoten todas las combinaciones lgicas posibles para ofrecer el conjunto completo de respuestas alternativas posibles a cada consulta efectuada. El ms difundido se denomina backtracking, que utiliza una estrategia de bsqueda de soluciones en estructuras de rboles denominada primero en profundidad.El motor de Prolog usa el mecanismo de backtracking para encontrar soluciones a una consulta. Supongamos que tenemos la siguiente base de conocimientos:hijo(homero,bart).hijo(homero,maggie).hijo(homero,lisa).item(bart,patineta).item(bart,gomera).item(lisa,saxo).copado(patineta).copado(saxo).itemCopadoDeHijo(Persona,Item):- hijo(Persona,Hijo), item(Hijo,Item),copado(Item).Si hacemos la consulta existencial:?-itemCopadoDeHijo(P,I).`P=homero,I=patineta;P=homero,I=saxo;false.Cmo se llega a esa solucin?El motor hace la consulta hijo(Persona,Hijo) que tiene 3 respuestas posibles en base a nuestros hechos. Por cada una de esas soluciones posibles iniciales tendr diferentes caminos por los cuales avanzar.1) Si Persona es homero e Hijo es bart: Se consulta item(bart,Item), que tiene dos respuestas posibles. Si Item es patineta, copado(patineta) se verifica, con lo cual es respuesta para itemCopadoDeHijo/2 Si Item es gomera, copado(patineta) no se verifica, con lo cual no es respuesta para itemCopadoDeHijo/2 2) Si Persona es homero e Hijo es maggie: Se consulta item(maggie,Item) que no se verifica, con lo cual no se avanza ms por este camino. Si Persona es homero e Hijo es lisa: Se consulta item(lisa,Item), que tiene una respuesta posible.3) Si Item se liga con saxo, copado(saxo) es cierto, con lo cual es respuesta para itemCopadoDeHijo/2." + +} , + +{ + +"title" : "Bagna cauda", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/bagna-cauda.html", +"date" : "", +"content" : "SalsaPara 25 a 30 personas 46 cabezas de ajo 2 frascos grandes de anchoas (no s bien cuntos gramos seran) 500cc de aceite de oliva 1/1.5 aceite girasol 8 potes de crema de 360cc un sobre de pimienta de 50 g un puadito de salNos faltaron las nueces, podra agregarse 1/4 kg de nueces.IngredientesPara 22/25 personas, entre ellos varios que andaban con ganas de esquivar las verduras: 2kg de carne saltada 2kg de salchicha con piel, tambin saltada igual que la carne. 1kg de ravioles saltados/fritos yo haba propuesto 12 baguetines de pan, no s cunto hubo al final. 4 plantas de apio 6 hinojos 1 repollo no muy grande 2 bandejas grandes de repollitos de bruselas (blanqueados 10 minutos en agua hirviendo, despus de dudar un poco les cortamos los cabitos) 2 plantas de brcoli (hervidos) 25 esprragos, saltados (es importante saltarlos en el momento). 3 kg de papines (hervidos primero y al horno despus). 4 morrones rojos y 2 verdes Impamente no conseguimos cardo.DiscusinHabamos calculado 25 personas, mirando lo que sobr creo que la salsa hasta 28-30 nos alcanzaba. Los ingredientes estuvieron bien para 25.Algunas cosas que se podran revisar en una repeticin: Aumentar la relacin anchoa/ajo. Le pondra por ah 30 cabezas de ajo y duplicara las anchoas. Me van a putear pero yo estara tentado de que no sea tan pesada. Para eso se podra reemplazar un poco de crema por leche. Lo que ms sobr fue el repollo, evidentemente era mucho. Las dems verduras anduvieron bien, sobr un poco de cada cosa. Carne, salchichas y ravioles se agotaron, pero no tuve sensacin de que faltaran. En la fase previa la gente se abalanz sobre el pan, pero una vez sobre la mesa ya no le dieron tanta bola. Al final me pareci que era un poco mucho. De las verduras la que ms gente escuch destacar fue el morrn. En segundo lugar pondra los repollitos (aunque quedaron bastantes en la olla). A m me gustaron mucho los esprragos. Casi nada de los ingredientes tena sal, creo que estuvo bien a lo mejor me qued con ganas de echarle un toque a los papines." + +} , + +{ + +"title" : "Bajar un proyecto maven de un repositorio git", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/bajar-un-proyecto-maven-de-un-repositorio-git.html", +"date" : "", +"content" : "DescripcinEste artculo asume la presencia de un entorno de trabajo con una JDK. En caso de no contar con un repositorio de esas caractersticas conviene leer las instrucciones para la preparacin de un entorno de desarrollo Java.Tambin se asume la preexistencia de un proyecto mavenizado y publicado en un repositorio Git, si lo que se desea es crear el proyecto en lugar de descargarlo, aqu estn las instrucciones para la creacin de un proyecto maven bsico y su posterior publicacin en el repositorio.El proceso tiene los siguientes pasos, que se detallan a continuacin: Clonar el proyecto desde el repositorio remoto y alojarlo en nuestro espacio de trabajo local. Adaptar el proyecto maven para ser utilizado dentro del entorno Eclipse.Descarga (clone)El checkout se puede hacer desde el eclipse desde un cliente git o por consolaA continuacin explicaremos los tres pasos por separado.Por lnea de comandoPara esto debemos ubicarnos en el directorio de trabajo saber la URL del repositorio en el que se public el proyecto$ cd ~/workspace/materia$ git clone https://github.com/uqbar-project/eg-vehiculos-xtendEn el directorio eg-vehiculos-xtend se bajan los recursos del proyecto, incluyendo un directorio .git donde est la informacin. De ser necesario debemos cambiar la rama o branch de trabajo, por ejemplo al branch dev:$ git checkout devDescarga desde el EclipseEn caso de hacerlo desde el eclipse, la forma de hacerlo es: Copiar en el portapapeles la URL del repositorio al que queremos apuntar Ir a la perspectiva Git En la solapa Git Repositories hacer click derecho sobre algn espacio en blanco y ah elegir la opcin Paste Repository Path or URI, luego botn Next Elegir una rama o branch para descargar (master por defecto), luego botn Next Seleccionar la carpeta del destino Chequear la opcin Import all Eclipse projects after clone finishesDescarga de un proyecto desde un cliente gitEso puede variar dependiendo del cliente, te dejamos algunos links Smartgit Source TreeAdaptar un proyecto maven para ser usado desde el EclipseSi importaste el proyecto desde la consola o bien el cliente solo descarg el proyecto en un espacio de trabajo local, lo que faltara hacer es File &gt; Import &gt; Existing Maven projectsLuego de posicionarse en el directorio donde descargamos el proyecto, en particular donde se encuentra el archivo pom.xml, seleccionamos dicho proyecto y luego presionamos el botn Finish.Entonces nuestro proyecto toma la definicin del pom.xml y se construye para ser usado en el IDE Eclipse. Vemos que la naturaleza del proyecto es Maven, porque tiene una M arriba del cono del proyecto:Y ya podemos comenzar a trabajar!" + +} , + +{ + +"title" : "Bibliografia sobre programacion avanzada orientada a objetos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/bibliografia-sobre-programacion-avanzada-orientada-a-objetos.html", +"date" : "", +"content" : "Herramientas de programacin y diseo Carlos Lombardi y Nicols Passerini, Introduccin a la Orientacin a Objetos, disponible en: https://drive.google.com/file/d/1RxqvJzyWSkJEl3_lzCMGWQhGkuXGWh2m/view?usp=sharing. Erich Gamma, Richard Helm, Ralph Johnson y John M. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley Professional Computing Series, 1994 Andrew Hunt y David Thomas, The Pragmatic Programmer: From Journeyman to Master, Addison-Wesley Professional, 1999. Alfred Aho, John Hopcroft y Jeffrey Ullman, Data Structures and Algorithms, Addison-Wesley, 1983 Steven John Metsker, William C.Wake, Design Patterns in Java, Software Patterns Series, 2006. Rebecca Wirfs-Brock, Alan McKean, Object Design: Roles, Responsibilities, and Collaborations, Addison-Wesley, 2002. Michael C. Feathers, Working Effectively with Legacy Code - Robert C.Martin Series, 2004. Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, Prentice Hall, 2008Herramientas metodolgicas Kent Beck, Test Driven Development: By Example, Addison-Wesley, 2002 Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software, Addison-Wesley Professional, 2003. Kent Beck y Cynthia Andres, Extreme Programming Explained: Embrace Change, 2nd Edition, Addison-Wesley, 2004 Martin Fowler, Kent Beck, John Brant y William Opdyke, Refactoring: Improving the Design of Existing Code, Addison-Wesley, 1999 Joshua Kerievsky, Refactoring to Patterns, Addison-Wesley, 2004" + +} , + +{ + +"title" : "Binding polimorfismo y sobrecarga", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/binding--polimorfismo-y-sobrecarga.html", +"date" : "", +"content" : "Qu entendemos por Binding?El binding es la relacin que se establece entre la invocacin a un procedimiento-funcin-mtodo y el cdigo que se ejecuta. Otro nombre que le damos es dispatch. Los conceptos de binding, polimorfismo y sobrecarga son aplicables a muchos paradigmas, y tienen diferentes formas de ser entendidos en cada uno de ellos. Por el momento, este artculo se concentra fundamentalmente en el paradigma de objetos.Dynamic method invocationEn objetos, cada vez que se enva un mensaje, el mtodo invocado depende del receptor. Por ejemplo, en Smalltalk:figuras:={Cuadradonew.Rectangulonew.Circulonew}.figurascollect:[:f|fsuperficie]Si las clases Cuadrado, Rectangulo y Circulo tienen cada una su propia implementacin de , cada vez que se enva el mensaje a la referencia el mtodo invocado ser uno distinto. Esta caracterstica es una de las ms importantes para el paradigma de objetos, ya que habilita algunas de sus herramientas ms interesantes.Tipo esttico y tipo dinmicoAl extender el concepto de dynamic method invocation a un lenguaje con chequeo esttico de tipos, es necesario tener en cuenta la informacin esttica que provee el sistema de tipos. En este tipo de lenguajes, a cada expresin se le asigna un tipo en forma esttica. Estos tipos se ejecutan para validar la correccin de los programas antes de su ejecucin y eliminar algunos posibles errores.El valor que tome la expresin en tiempo de ejecucin puede diferir del valor que es asignado a esa expresin en forma esttica. Por ejemplo:publicinterfaceFigura{publicdoublegetSuperficie();}publicclassCirculoimplementsFigura{@OverridepublicdoublegetSuperficie(){...}publicdoublegetRadio(){...}}Figuraf=newCirculo();Estticamente, la variable tiene el tipo , pero cuando ese programa se ejecute, el valor de ser un Circulo. La asignacin code|Figura f = new Circulo() es vlida siempre que sea un subtipo de . A esta regla se la conoce como subsumption.La presencia de tipado esttico nos obliga a analizar nuestro cdigo desde las dos perspectivas. Al evaluar se enva el mensaje al objeto referenciado por la variable y por lo tanto se ejecutar el mtodo de la clase . Sin embargo, en el momento de chequear tipos se controla que el tipo de , que es contenga el mensaje enviado.Si intentamos evaluar se producira un error de compilacin, porque esa expresin no pasa el chequeo de tipos. Por eso, decimos que la regla de subsumption conlleva una prdida de informacin de tipos. El objeto referenciado por entiende el mensaje , sin embargo el chequeador de tipos no puede verificar eso y rechaza el programa.SobrecargaSe dice que un nombre de mtodo est sobrecargado en un contexto cuando es utilizado para representar dos o ms mtodos o funciones distintos, que se diferencian por su tipo. El tipo de un mtodo incluye tanto a los tipos de los parmetros como al del valor de retorno. Por ejemplo: En Haskell es posible definir funciones con el mismo nombre y distintos tipos de parmetros o distinto tipo de retorno. En Java o C# es posible definir dos mtodos en la misma clase o jerarqua con distinto nmero de parmetros o con parmetros de distinto tipo. (La posibilidad de sobrecargar mtodos variando el tipo de retorno es menos frecuente en el paradigma de objetos.)Por ejemplo el mtodo est sobrecargado en la clase .classC{voidm(Figuraf){println(1);}voidm(Circuloc){println(2);}}Cuando se enva un mensaje que est sobrecargado, el sistema debe decidir cul es el mtodo que se debe ejecutar. En la mayora de los lenguajes orientados a objetos, esta decisin se toma en forma esttica. (Cuando la decisin es dinmica, en lugar de sobrecarga hablamos de Multimethods. Por ejemplo, en la siguiente porcin de cdigo, al evaluar se ejecutar el mtodo que recibe una figura, y no el que recibe un crculo; y por lo tanto imprimir 1.Figuraf=newCirculo();Cc=newC();c.m(f);//=&gt;imprime1!La interpretacin que debemos hacer es que que en realidad el mensaje enviado no se identifica nicamente por su nombre, sino que incluye los tipos de los parmetros. Desde esta perspectiva los dos mtodos de la clase tienen distinto nombre, son totalmente independientes uno del otro. Debemos interpretar que el primero se denomina y el segundo . En presencia de este tipo de sobrecarga el mtodo a ejecutar se decidir en tiempo de ejecucin, en funcin del mensaje enviado, pero el mensaje a enviar se decide en tiempo de compilacin, a partir de la informacin de tipos disponible en este momento. En resumen, el mensaje enviado a no es sino . Dado que ambos mtodos tienen identificadores distintos, para invocarlos se envan mensajes distintos y la decisin entre ambos ser tomada en tiempo de compilacin.Veamos un ejemplo ms complejo con sobrecarga y redefinicin (adaptado de Foundations of Object-oriented Languages: Types and Semantics por Kim Bruce), tenemos el siguiente cdigo en Scala:classC{defm(other:C)={println(1)}}classSCextendsC{defm(other:SC)={println(3)}overridedefm(other:C)={println(2)}}Si hacemos la siguiente prueba:varc2:C=newSC()varsc:SC=newSC()c2.m(sc)El resultado ser 2, no 3, ya que el mensaje que se elige estticamente no es m(SC), sino m(C). Para entender lo que sucede podemos hacer dos pasos bien separados: Pensar primero como compilador y despus pensar como mquina virtual (pensar en tiempo de compilacin y tiempo de ejecucin).Empecemos como compiladores: c2 es una variable del tipo C, y sc es una variable del tipo SC. En c2 se referenciar a una instancia del tipo SC, pero eso como compiladores por ahora no nos importa, porque no estamos ejecutando el cdigo.Luego vamos a esta llamada:Ac es donde empieza la confusin: Uno piensa que porque sc es del tipo SC y c2 es una instancia de SC (si bien la variable es de tipo C) el mtodo que se va a ejecutar es m(SC), pero no es as. Por qu? La respuesta viene de pensar como compilador, no ejecutar el cdigo y mirar la el tipo de la variable c2, y deducir de ah los posibles mensajes que entiende, y de ver bien la firma de esos mensajes.De qu tipo es C2? Del tipo C. Qu mensajes entiende un objeto del tipo C? Vamos a ver la declaracin de C:classC{defm(other:C)={println(1)}}Los objetos del tipo C slo entienden un mensaje, y ese es m(C). Por lo tanto, siendo que SC es un subtipo de C, la firma del mensaje que va a ser llamado en va a ser m(C):Unit y no m(SC):Unit, dado que el tipo C no tiene definido ningn mensaje con parmetro SC. Esa firma es decidida en compilacin y depende slo de los tipos declarados/inferidos de las variables, y no de las instancias.Ahora sabemos la firma, terminamos de compilar el cdigo. Pasemos al modo ejecucin y pensemos como mquinas virtuales Qu mtodo se ejecuta al hacer c2.m(sc)? Para saberlo, no hay que hacer otra cosa que method lookup. Cul es la firma del mensaje c2.m(sc)? La firma es m(C):Unit (por lo que vimos antes en compilacin. A quin le estoy enviando ese mensaje? Al objeto referenciado por c2, que es una instancia de la clase SC. Para saber qu mtodo ejecutar entonces, comenzamos el method lookup a partir de la clase SC. classSCextendsC{defm(other:SC)={println(3)}overridedefm(other:C)={println(2)}} Tiene SC algn mtodo definido cuya firma sea m(C):Unit? S. Entonces ese es el mtodo que se va a ejecutar, que es el que imprime 2.Eso sera bsicamente todo. Lo importante de todo esto es entender que ahora los tipos son mucho ms importantes para la construccin de mi modelo conceptual. Y la idea es que con ejercicios como estos uno comprueba si entendi o no que los tipos me cambian un poquito la semntica del cdigo y me agregan algo ms en lo que tengo que pensar, si bien me previenen algunos errores en compilacin.EjemplosTres ejemplos del lenguaje Java: Al mandar un mensaje a dos objetos (polimrficos) distintos, el binding es dinmico. Si un objeto recibe dos mensajes con el mismo nombre pero distintos tipos de parmetros, el bingind es esttico. A esto lo llamamos sobrecarga. Si invocamos un mtodo de clase, el binding es esttico.Algunas variantes En C++ o C# si no les pongo virtual a los mtodos el binding es esttico. En Eiffel se da dinmicamente, a esta caracterstica la denominamos multimethods. En Smalltalk el binding de los mtodos de clases es tambin dinmico. (Y esto es uno de los motivos que nos da pie a decir que las clases en Smalltalk son realmente objetos, mientras que en Java no es as.)" + +} , + +{ + +"title" : "Bloques", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/bloques.html", +"date" : "", +"content" : "Qu es un bloque?Un bloque (tambin conocido como closure) es un objeto, y por lo tanto podemos hacer con l lo mismo que hacamos con los dems objetos esto es: Enviarle mensajes Pasarlo como parmetro de algn mensaje Hacer que una variable lo referencieUn objeto bloque representa un cacho de cdigo que no se ejecut, ese cdigo solo se ejecutar si alguien le manda un mensaje que le indique hacerlo. Veamos algunos ejemplos en el lenguaje Wollok:Si ejecutamos las siguientes instrucciones:varx=0{x=x+1}A qu objeto apunta la variable x despus de ejecutar esas 2 lneas de cdigo? Claro, al objeto cero (0)! Porque slo creamos el bloque, pero el cdigo del mismo nunca se evalu.Para que la variable x apunte al objeto uno (1) tenemos que decirle al bloque que se ejecute.varx=0{x=x+1}.apply()Ahora s, despus de ejecutar esas 2 lneas de cdigo la variable x va a apuntar al objeto uno (1). Es importante darse cuenta que apply() es un mensaje que le llega al objeto bloque. Este mensaje hace que se ejecute el cdigo que est dentro del bloque y que se retorne el objeto devuelto por la ltima sentencia del bloque.Conocimiento del contextoAlgo que se pone en evidencia en este ejemplo introductorio es que los bloques tienen una nocin del contexto en el cual fueron definidos, y por eso es que tienen acceso a las referencias disponibles en dicho contexto. Es por eso que es posible usar la variable x que haba sido definida fuera del bloque.Si tuviramos el siguiente cdigo:object pepita { var energia = 100 method volar(metros) { energia -= 10 - metros } method irYVolverNVeces(metros, veces){ veces.times({n =&gt; self.volar(metros * 2) }) }}Y luego evaluamos: pepita.irYVolverNVeces(5, 3)El mensaje times(algoParaHacer) que se le manda al nmero 3 con el bloque que construmos en ese momento se encargar de mandarle el mensaje apply(valor) al bloque que le pasamos, en este caso, 3 veces. Dado que la referencia metros exista en el contexto en el cual ese bloque fue creado (era un parmetro del mtodo), es vlido usar esa referencia dentro de la lgica del bloque y va a apuntar al objeto 5, como es de esperarse. El parmetro que se usa para aplicar el bloque ser primero 1, luego 2 y finalmente 3. Esta informacin es irrelevante para el ejemplo, pero el bloque debe recibir un parmetro para que entienda el mensaje que recibir cuando se evale el mtodo times.Otra pregunta interesante es: quin es self dentro del bloque?Cuando usamos self dentro de un bloque, estamos referenciando al mismo objeto que recibi el mensaje dentro del cual se cre el bloque (o sea, pepita), lo cual es muy convieniente ya que hace que no necesitemos parametrizar a self si necesitamos mandarle mensajes o parametrizarlo a otro mensaje dentro del cdigo del bloque.Finalmente, el resultado de la operacin ser que la energa de pepita se habr decrementado en 60.Bloques como funcionesTambin se puede ver a los bloques como objetos que representan una funcin sin nombre (o sea, una funcin annima, como las Expresiones lambda de funcional!).El bloque { 1 } en Wollok es como una funcin constante que siempre devuelve 1 si le decs que se ejecute. Pero el chiste de las funciones es que reciban parmetros y los bloques tambin pueden recibir parmetros, por ejemplo la sintaxis de Wollok para un bloque de dos parmetros es {parametro1,parametro2=&gt;cuerpoDelBloque}Ejemplos:Podramos representar las siguientes funcionesf(x)=2xg(x,y)=x2+y2 con bloques de la siguiente forma:varf={x=&gt;2*x}varg={x,y=&gt;x**2+y**2}Cmo hacemos para usar bloques que tienen parmetros? Por ejemplo si quisiramos los equivalentes a evaluar las funciones f(4) y g(4,3)f.apply(4)//Estodevuelveelobjeto8g.apply(4,3)//Estodevuelveelobjeto25Por lo general el uso que le damos a los bloques es slo la creacin de los mismos para pasar por parmetro a funcionalidad ya existente de propsito general, como son los mensajes de colecciones Mensajes de colecciones, y no tanto la aplicacin de los mismos. Sin embargo es interesante saber cmo es que las colecciones son capaces de evaluar lo que les pedimos.Para pensar: Los mensajes que esperan por parmetro un bloque, podrn recibir por parmetro un objeto programado por nosotros? Qu es lo que una coleccin necesita realmente que le pasemos por parmetro para poder realizar un filtrado?Cmo funciona el #ifTrue: y el #ifFalse: de Smalltalk?En el caso de Smalltalk, el uso de bloques es an ms generalizado, ya que al no existir estructuras de control y tener una sintaxis completamente basada en mensajes a objetos, los bloques se usan por ejemplo para poder saber qu hacer en un condicional cuando la condicin se cumple o no se cumple. Esto se logra mediante ditintos mensajes que entienden los booleanos que representan la condicin sobre la cual queremos decidir.Si en un workspace escribimospepitaenergia&gt;0ifTrue:[pepitacome:30]Pensando en trminos de objeto y mensaje (mensaje = selector + parmetros), qu est pasando ac?El objeto receptor del mensaje ifTrue: es el objeto que me devuelve pepita energia &gt; 0, ese objeto puede ser true o false.Si el receptor es true queremos que el bloque [ pepita come: 30 ] se ejecute. Si el receptor es false NO queremos que el bloque [ pepita come: 30 ] se ejecute.Entonces el objeto que tiene la responsabilidad de saber si el bloque debe o no ejecutarse es el booleano receptor del mensaje ifTrue:.Siendo false la nica instancia de la clase False y true la nica instancia de la clase True, la implementacin del mtodo ifTrue: en cada una de las clases esTrue&gt;&gt;ifTrue:unBloque"selfapuntaatrueentoncesqueremosqueseejecuteelbloque"^unBloquevalue False&gt;&gt;ifTrue:unBloque"selfapuntaafalseentoncesNOqueremosqueseejecuteelbloque"^nilO sea que las estructuras de control a las que estbamos acostumbrados por el paradigma estructurado, no son ms que mensajes polimrficos :smile:. Todo sigue las mismas reglas, objetos y mensajes." + +} , + +{ + +"title" : "Brownies", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/brownies.html", +"date" : "", +"content" : "Ingredientes: Chocolate, 150 gramos Manteca, 100 gramos Azcar, casi una taza Huevos, 2 Harina, 1/2 tazaPasos: Ponga la manteca y el chocolate (cortado en trozos) dentro de una sartencita; derritalos en el horno. Bata los huevos con el azcar hasta que estn bien cremosos y la superficie llena de globitos. Agrgueles el chocolate derretido y tibio; contine batiendo hasta que vuelvan a formarse globitos. NOTA: El chocolate tiene que estar bien mezclado con la manteca porque sino no queda homogneo. Esa es la parte mas delicada, que el chocolate no se queme ni se pegue (consejo, poner manteca abajo del chocolate para derretirlo). Del mismo modo incorprele la harina. Vierta en una asaderita enmantecada y enharinada de tamao tal que la preparacin quede de 2.5 cm de alto (mas o menos). Cocine en horno bien caliente hasta que la superficie parezca craquele y la preparacin este firme pero hmeda. NOTA: Esta es una parte sensible es cuando se cocina, porque si se cocina mucho queda duro. La teora dice que hay que dejarlo en el horno sin abrirlo como media hora, y debera primero como inflarse y despus baja y se craquela (ah ya se lo puede pinchar con un escarbadiente en el medio para ver si est cocinado, y tiene que quedar hmedo). Retire del horno y deje enfriar en la asadera.Una receta alternativaMuy chocolatosa y muy hmeda Chocolate cobertura, 450 gramos (ojo, no cobertura de chocolate) Manteca, 170 gramos Azcar, 340 gramos (con azcar comn se genera una costra ms gruesa, con impalpable se consigue una costra ms delicada). Huevos, 2 (mezclar con el azcar sin batir, para que no quede esponjoso, es ms denso que un bizcochuelo) Harina, 70 gramos (comn 0000, no leudante ni polvo de hornear) Nueces, 100 gramos Se le puede poner esencia de vainilla.Tambin se propone poner papel manteca en la placa. Horno bastante caliente (un poco ms que medio), de 20 a 25 minutos.Otra opcin ms tipo masita: 6 huevos 300 chocolate 200 manteca 170 harina cacao nueces, 100 gramos esencia de vainillaOtra receta alternativaAKA la del asado familiero (los pasos son similares o iguales al anterior) Ingredientes: 4 huevos 1 taza y un toque ms de harina (preferentemente 0000, y comn) 2 tazas de azcar 150 gr de chocolate (recomiendo guila) 150 gr de mantecaPasos: 1 - Derretir manteca y chocolate en el microondas. 2 - Romper los huevos (oh si) en un bowl y mezclarlos muy bien con el azcar. 3 - Mezclar lo del paso 1. con lo del paso 2. Seguir mezclando. 4 - Agregar harina. Seguir mezclando, dije! 5 - En este paso agregaran nueces, almendras o lo que guste. 6 - Yo le pongo manteca y harina al molde porque da fiaca si se pega, aunque no debera pegotearse demasiado por la cantidad de manteca que lleva. 7 - Al horno! Depende el horno y soy muy inexperta, as que voy tanteando con el cuchillo. En general, cuando tiene la parte de arriba crocante y el cuchillo no sale chorreando, ya est bien." + +} , + +{ + +"title" : "C ++", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/c--.html", +"date" : "", +"content" : "Sobre el lenguaje C++ (wikipedia)" + +} , + +{ + +"title" : "C", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/c.html", +"date" : "", +"content" : "Sobre el lenguaje: C# (Wikipedia)Herramientas basadas en C#: Mono" + +} , + +{ + +"title" : "Calculo del tipo de una funcion en haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/calculo-del-tipo-de-una-funcion-en-haskell.html", +"date" : "", +"content" : "IntroduccionDado que el haskell es un lenguaje con Inferencia de tipos, no es necesario indicar el tipo de las funciones que construimos. A pesar de ello (o tal vez precisamente por ello) los tipos juegan un rol fundamental al programar en un lenguaje funcional (en particular en Haskell).El sistema de tipos de Haskell es muy estricto, bastante ms de lo que estamos acostumbrados los que venimos de la programacin orientada a objetos. Si bien en algunos casos puede ser molesto porque un tipado tan estricto como el de Haskell complica algunas operaciones sencillas como suele pasar con el clculo de un promedio, en la amplia mayora de los casos es bueno porque nos ayuda a detectar errores ms tempranamente.Esto obliga al programador a ser ms atento con los tipos de cada una de las funciones que programa o que utiliza. Los siguientes aspectos de tipado son importantes a tener en cuenta a la hora de entender de qu tipo son las funciones que definimos:La construccin de funciones a partir de funcionesEl paradigma funcional tiene como uno de sus pilares la posibilidad de construir funciones complejas a partir de combinar funciones ms simples (utilizando composicin, aplicacin parcial, orden superior, etc); para poder utilizar cualquiera de esas herramientas es necesario tener presente el tipo de las funciones que quiero combinar, por ejemplo: Si quiero componer dos funciones f y g: es necesario que la imagen de f est incluida en el dominio de g (tal como aprendimos en matemtica). Al aplicar una funcin de orden superior es necesario que matcheen los tipos de la funcin esperada con la funcin recibida.El polimorfismo paramtrico y las type classesUna funcin que tiene un tipo genrico al ser aplicada puede reducir su tipo, eso tambin es algo a tener en cuenta.Por ejemplo la funcin filter puede en principio procesar listas de cualquier tipo; en cambio una vez que yo le aplico el primer parmetro (el criterio de seleccin) ese tipo se restringe. Si el criterio fuera even, ese filtrado slo va a servir para listas de valores numricos, porque even restringe el tipo de los elementos de la lista a el tipo de lo que espera recibir, que es un nmero.A continuacin se describen paso a paso los ejemplos que permiten comprender el mecanismo de inferencia utilizado en el lenguaje Haskell.Ahora s: cmo inferimos el tipo de una funcin?Antes de poder evaluar el tipo de una hay que comprender cules son los tipos posibles de Haskell, eso est explicado en el artculo sobre Tipos de Haskell, y entender la regla bsica de tipado para una aplicacin: si x es Bool, entonces not x tambin es de tipo Bool, porque not :: Bool -&gt; Bool; si x es de cualquier otro tipo not x no tipa.Funciones SimplesAl intentar calcular el tipo de una funcin, lo primero que tenemos que hacer es mirar las funciones que se usan dentro de su definicin y asegurarnos de saber de qu tipo son esas funciones. Luego las preguntas importantes son: Cuntos parmetros recibe? Esto ayuda a ordenarnos, para saber cuntos huecos tenemos que llenar, que es esa cantidad + 1, por el tipo de retorno. De qu tipo son esos parmetros? Esto se deduce en base al uso de los mismos en la definicin. De qu tipo es lo que retorna? Esto se deduce en base a lo que retorna la funcin principal que es la de ms afuera o menor precedencia.Por ejemplo:nonexy=notx&amp;&amp;noty-- Sabemos que:-- not :: Bool -&gt; Bool-- (&amp;&amp;) :: Bool -&gt; Bool -&gt; BoolLuego, para determinar el tipo de la funcin none podemos seguir los siguientes pasos: Vemos que tiene dos parmetros (x e y), entonces podemos decir que su tipo tiene que tener la forma none :: ?? -&gt; ?? -&gt; ??, luego tendremos que calcular cules son esas incgnitas. Analizamos el tipo de los parmetros: Si x es utilizado como parmetro de la funcin not, podemos deducir que x no admite valores de cualquier tipo, slo pueden ser booleanos. Por ende: none :: Bool -&gt; ?? -&gt; ??. Un razonamiento anlogo nos lleva a deducir que y tambin debe ser un valor booleano. Luego: none :: Bool -&gt; Bool -&gt; ??. Finalmente, para saber el tipo de retorno: Dado que x es Bool, entonces not x tambin es de tipo Bool, al igual que not y, lo cual es compatible con lo que espera el (&amp;&amp;) (o sea que la expresin notx&amp;&amp;noty tipa). Lo que retorna la funcin (&amp;&amp;) al estar totalmente aplicada es Bool, y esa es la funcin principal, as que podemos afirmar que: none :: Bool -&gt; Bool -&gt; Bool. En el ltimo paso podemos ver que en realidad para saber el tipo de no sera necesario mirar los parmetros de (&amp;&amp;), con saber su tipo de retorno sera suficiente. Sin embargo el anlisis es til para asegurarnos de que la funcin es correcta, y en caso de incurrir en errores de tipos, entender la causa.Por otro lado, en ejemplos ms complejos analizar los parmetros de las funciones usadas en la definicin ser indispensable para poder saber el tipo de retorno (por ejemplo en la presencia de polimorfismo).Ejemplo un poco mas heavySiendof x y z = (head y) &gt; (map (&#92;n -&gt; n x) z)Vamos a intentar hacer la inferencia de tipos. Primero tenemos que ver qu es f? f es una funcin que tiene 3 parmetrosPonemos 3 flechitas simples: -&gt;f::estoeseltipodex-&gt;estoeseltipodey-&gt;estoeseltipodez-&gt;estoeseltipodeloquedevuelvefComo head :: [a] -&gt; a, y tiene que ser una listaf::estoeseltipodex-&gt;[???]-&gt;estoeseltipodez-&gt;estoeseltipodeloquedevuelvefComo map :: (a -&gt; b) -&gt; [a] -&gt; [b], z tiene q ser una lista porque se usa como su segundo parmetrof::estoeseltipodex-&gt;[???]-&gt;[???]-&gt;estoeseltipodeloquedevuelvefLa funcin (&#92;n -&gt; n x) que es primer parmetro del map recibe como parmetro cada elemento de la lista z, cada uno de esos elementos va a ser n. Y como n se est aplicando a x podemos inferir que n es una funcin, por lo que z es una lista de funcionesf::estoeseltipodex-&gt;[???]-&gt;[??? -&gt; ???]-&gt;estoeseltipodeloquedevuelvefComo x es el parmetro de n podemos inferir que x pertenece al dominio de n, por ende si el su dominio es de tipo a entonces x es de tipo af::a-&gt;[???]-&gt;[a-&gt;???]-&gt;estoeseltipodeloquedevuelvefRespiremos profundo Asumimos que la imagen de las funciones de la lista es de tipo b, porque slo a partir de map (&#92;n -&gt; n x) z no vemos nada que lo restrinja a tipos concretos, ni que deba ser del mismo tipo que su dominio al cual denominamos af::a-&gt;[???]-&gt;[a-&gt;b]-&gt;estoeseltipodeloquedevuelvefAhora pensemos en los parmetros de la funcin (&gt;) :: Ord a =&gt; a -&gt; a -&gt; a que son (head y) y (map (&#92;n -&gt; n x) z): Para poder comparar estas 2 cosas, ambas expresiones tienen que ser del mismo tipo El map me da una lista de lo que devuelve (&#92;n -&gt; n x) sabemos que la imagen de (&#92;n -&gt; n x) es b entonces map (&#92;n -&gt; n x) z es de tipo [b] Por ende (head y) tambin es de tipo [b] Para que (head y) sea de tipo [b], y tiene que tener el tipo [[b]] A su vez b debe pertenecer a la typeclass Ord (por la restriccin impuesta por la funcin (&gt;))f::Ord b =&gt; a-&gt;[[b]]-&gt;[a-&gt;b]-&gt;estoeseltipodeloquedevuelvefLa funcin principal de f es (&gt;), como la imagen de (&gt;) al estar totalmente aplicado es Bool la imagen de f es Boolf::Ord b =&gt; a-&gt;[[b]]-&gt;[a-&gt;b]-&gt;BoolEjemplo de parcial para pensarTenemos esta funcin:fabcd=maximoSegun(cd).filter(==snda).mapbY sabemos que:*Main&gt;:tmaximoSegunmaximoSegun::Orda1=&gt;(a-&gt;a1)-&gt;[a]-&gt;aCul es el tipo de f? Ayudita: pensar cul es la funcin principal en este ejemplo. Si no sabs bien qu est pasando, te recomendamos leer sobre notacin point-free." + +} , + +{ + +"title" : "Calidad de las pruebas unitarias", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/calidad-de-las-pruebas-unitarias.html", +"date" : "", +"content" : "IntroduccinLas pruebas unitarias son una herramienta fundamental en el desarrollo de software. Con ellas es posible: Encarar refactors y correcciones con mayor seguridad Mantener una especificacin viva del sistema Confirmar la presencia de errores del sistema Guiar nuestro diseo (si se emplea TDD)El poder de las pruebas radica en que son, justamente, cdigo (y no, por ejemplo, una especificacin en un bibliorato), lo cual las vuelve facilmente automatizables. Y como se encuentra normalmente junto con el cdigo productivo, los cambios en las especificaciones del mismo sern detectados rpidamente.Sin embargo, al tratarse de cdigo, un desarrollo poco cuidado de los casos de pruebas puede introducir problemas similares a los que surgen con el cdigo productivo en los siguiente aspectos: Expresividad: las pruebas se son ilegibles, los programadores no entienden lo que se est probando Correctitud: las pruebas no validan lo que deberan, o, peor, lo hacen de forma incorrecta o no repetible. Nivel de abstraccin: las pruebas no tienen el nivel de abstraccin suficiente, y repiten lgica, lo cual lleva a contar con muchos necesarios para una buena cobertura, pero casos extremadamente parecidosLo cual llevar a severos problemas de mantenibilidad de los tests y a eslganes y prcticas tan aviesas como test que se rompe, test que se elimina. As nuestra preciada cobertura desaparecer sin avisar.La moraleja es entonces que el nivel de calidad de las pruebas unitarias debe ser similar al del cdigo productivo.Nivel de abstraccin justoTests abstractosAserciones personalizadasDelegar apropiadamente" + +} , + +{ + +"title" : "Cannot construct the infinite type", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/cannot-construct-the-infinite-type.html", +"date" : "", +"content" : "Advertecia: esto es un borradorEl problemaQue hace la siguiente funcin?autoAplicarfuncion=funcionfuncionOK, y que tipo tiene?autoAplicar::(a-&gt;a)-&gt;(a-&gt;a)??Si lo cargamosOccurscheck:cannotconstructtheinfinitetype:a=a-&gt;aWhengeneralisingthetype(s)for`f'A que intenta generalizar?1.porxx,xesunfuncion2.xselepasaunargumento,esunafuncionde"unparametro"3.autoAplicar::(?-&gt;?)-&gt;?4.porxx,xtienequesercapazderecibirunafunciondetipoxporparmetro.Entoncessix::a-&gt;?,a==a-&gt;?5.entoncesx::a-&gt;?==(a-&gt;?)-&gt;?==((a-&gt;?)-&gt;?)-&gt;?==(((a-&gt;?)-&gt;?)-&gt;?)-&gt;?.....Otra vuelta de tuercaSin embargo. si pudieramos desactivar el chequeo de tipos. esto tiene sentido?autoAplicarididididS!Es ms, si slo lo desactivaramos para autoAplicar:autoAplicarid&lt;-notipaidid&lt;-tipa!!idMoraleja: el sistema de tipos puede rechazar programas vlidostype vs data/newtype" + +} , + +{ + +"title" : "Cantidad de parametros de una funcion en haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/cantidad-de-parametros-de-una-funcion-en-haskell.html", +"date" : "", +"content" : " REDIRECCIN Notacin point-free" + +} , + +{ + +"title" : "Categorias", +"category" : "", +"tags" : "", +"url" : "/wiki/internal/categories.html", +"date" : "", +"content" : "Descripcin de categoriasMotivacinTODO" + +} , + +{ + +"title" : "Ciclo de vida de un objeto", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ciclo-de-vida-de-un-objeto.html", +"date" : "", +"content" : "Es importante reconocer el ciclo de vida de un objeto, ya que el estado que puede guardar un objeto depende de eso.Tipos de ciclo de vida puede haber mucho, a modo de ejemplo podemos mencionar tres muy comunes: Objetos permanentes, singletons, servicios. Son objetos que duran toda la vida del sistema (con variantes). En general nacen con el sistema y no pueden ser agregados nuevos, son compartidos por todos los usuarios del sistema. Estos son los que tienen el ciclo de vida ms largo y no pueden tener ningn tipo de estado conversacional. Objetos persistentes o entidades: Son los que representan los datos que guardamos de nuestro negocio, las entidades permanentes, por ejemplo en un video club me guardo los socios, las pelculas. Tpicamente el ciclo de vida es darlos de alta, modificarlos, eventualmente se pueden dar de baja. A veces la baja es lgica. Objetos transientes o procesos: Son los que guardan informacin sobre un proceso que se est llevando a cabo. El proceso puede ser tan corto como el procesamiento de un evento de teclado o mouse o un proceso de negocio que dura meses. Sin embargo los objetos persistentes no deberan guardar informacin de un proceso puntual, ya que esto es fuente de errores. En general los objetos con ciclos de vida ms largos no pueden tener referencias a objetos de ciclo de vida ms corto puntuales. Una vez terminados, estos objetos a veces se guardan como histrico. Un objeto persistente s puede tener referencia a los procesos histricos o bien a los procesos en curso.En una aplicacin web suelen aparecer objetos cuyo ciclo de vida est asociado a un request o a una session.Esto es anlogo a un anlisis de cardinalidad o normalizacin, se podra extender por ese lado." + +} , + +{ + +"title" : "Clase abstracta vs interfaces", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/clase-abstracta-vs-interfaces.html", +"date" : "", +"content" : " REDIRECCIN Clase abstracta vs interfaz" + +} , + +{ + +"title" : "Clase abstracta vs interfaz", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/clase-abstracta-vs-interfaz.html", +"date" : "", +"content" : "DefinicionesClase abstractaUna clase abstracta es una clase que no tiene instancias. Su utilidad consiste en proveer estructura y comportamiento comn a todas las subclases que heredan de ella.publicabstractclassFigura{finalpublicbooleanmenorQue(FiguraotraFigura){returnthis.getArea()&lt;otraFigura.getArea();}publicabstractdoublegetArea();publicabstractdoublegetPerimetro();}Si tenemos la clase Rectngulo, Crculo, etc. que heredan de Figura todas se benefician del comportamiento default para el mtodo menorQue que permite comparar una figura con otra. Por otra parte los mtodos que resuelven el rea y el permetro son abstractos, no se provee una implementacin sino que deben ser codificados por las subclases.InterfazUna interfaz permite especificar un contrato (formado por un conjunto de operaciones). Las clases que adhieren a ese contrato deben implementar esos mtodos./**Implementingthisinterfaceallowsanobjecttobethetargetof*the"foreach"statement.*@since1.5*/publicinterfaceIterable&lt;T&gt;{/***ReturnsaniteratoroverasetofelementsoftypeT.**@returnanIterator.*/Iterator&lt;T&gt;iterator();}En este ejemplo del lenguaje Java las clases que implementen la interfaz Iterable deben definir un mtodo iterator(). Todos los mtodos son abstractos, ya que la interfaz slo declara la firma de cada uno de los mtodos: nombre, parmetros que recibe, tipo que devuelve y excepciones que puede arrojar.ComparacinTanto la clase abstracta como la interfaz definen un tipo, pero mientras que el objetivo al definir una clase abstracta es reutilizar comportamiento, en la interfaz la idea principal es posibilitar el polimorfismo entre clases que no tienen cosas en comn. Dependiendo del lenguaje, es posible que tengamos restricciones para crear mtodos o atributos sobre una interfaz.Recordemos que en la mayora de las tecnologas se trabaja nicamente con herencia simple (solamente es posible heredar de una nica superclase), mientras que una clase puede tener mltiples tipos (implementar diferentes interfaces). Entonces en esos casos donde la herencia es una herramienta rgida, que permite una sola chance para ordenar la jerarqua de objetos, la interfaz puede resultar una alternativa viable." + +} , + +{ + +"title" : "Clases anonimas en java", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/clases-anonimas-en-java.html", +"date" : "", +"content" : "Motivacin: ausencia de bloquesLa motivacin ms importante para entender las clases annimas es la ausencia bloques (o closures) en el lenguaje Java. Java 8 recin es la primer versin que introduce un mecanismo de bloques (ver Lambdas_en_Java_8)Veamos un ejemplo:En smalltalk para seleccionar los elementos de una coleccin que cumplen cierta condicin enviamos el mensaje select: Por ejemplo, para obtener las personas mayores de 18 aos haramos:personasselect:[:p|pedad&gt;18]Ejemplo en Java Sin clases annimasCmo haramos eso en java ?Primero que nada no existe un mtodo select ni nada parecido en las colecciones (interfaz Collection). As que tenemos que hacer el mtodo nosotros.Hacemos un mtodo esttico como una utilidad, al que le tenemos que pasar la coleccin como parmetro.publicclassCollectionUtils{publicstaticCollection`select(Collection``coleccion,&lt;&lt;&lt;&lt;condicion&gt;&gt;&gt;&gt;){``...``}``}`Obviamente tambin tenemos que pasarle de alguna forma la condicin !Ahora bien, en Java no existen los bloques o closures, con lo cual, la nica opcin que tenemos es pasar un objeto. As que tenemos que modelar el concepto de Condicion.publicinterfaceCondicion{publicbooleancumple(Objectobj);}Como la condicin es lo que va a tener que implementar el usuario de este mtodo, es decir quien quiera filtrar una coleccin, la definimos como una Interfaz de java, para no poner una restriccin sobre una superclase (la otra opcin sera que fuera una clase abstracta). Fjense que es un objeto que tiene una [http://en.wikipedia.org/wiki/Single_responsibility_principle [nica responsabilidad]] bien identificada. Dado un objeto que le paso por parmetro me sabe decir si cumple o no con la condicin. Entonces hacemos una primer implementacin de nuestro ejemplo de filtrar mayores de 18 creando una clase normal que implemente esa interfaz.classMayorDe18CondicionimplementsCondicion{@Overridepublicbooleancumple(Objectobj){return((Persona)obj).getEdad()&gt;18;}}Y para filtrar una coleccinpersonas=...CollectionUtils.select(personas,newMayorDe18Condicion());Incluso si usamos los imports estticos de Java, podemos importar mtodos estticos de una clase, para no tener que llamarlos con el nombre de la clase, punto, y el mtodo. Quedaraimportstaticorg.uqbar-project.CollectionUtils.select;...personas=...select(personas,newMayorDe18Condicion());Ok, igualmente sigue siendo mucho ms burocrtico y pesado que la implementacin en smalltalk.Igualmente, lo que ms nos molesta es que tenemos que crear una nueva clase por cada condicin por la que querramos filtrar. Es bastante molesto eso. Ejemplo, queremos filtrar las personas casadas..classEsCasadaCondicionimplementsCondicion{@Overridepublicbooleancumple(Objectobj){return((Persona)obj).esCasada();}}Y luegocasados=select(personas,newEsCasadaCondicion());Accediendo a referencias de otro Objeto (sin annimas)Qu pasa si ahora queremos desde la condicin utilizar una estado interno del objeto que est filtrando. Por ejemplo, desde una Empresa, queremos obtener sus empleados. Para eso, filtramos de la coleccin de personas a aquellas que trabajen para esta empresa.publicclassEmpresa{publicCollectiongetEmpleados(){returnselect(personas,newTrabajaEnCondicion(this));}}Como se ve necesitamos pasarle la empresa a la condicin. Es una condicin que tiene estado. En este caso se pasa a s mismo todo el objeto Empresa.classTrabajaEnCondicionimplementsCondicion{privateEmpresaempresa;publicTrabajaEnCondicion(Empresaempresa){this.empresa=empresa;}@Overridepublicbooleancumple(Objectobj){return((Persona)obj).getEmpleador()==this.empresa;}}Cada vez ms cdigo ! :S Necesitamos declarar el atributo (estado interno) y recibirlo en el constructor.Bastante burocrtico nuvamente. En smalltalk seraEmpresa&gt;&gt;empleados^personasselect:[:p|(pempleador)=self]Accediendo a referencias locales (sin annimas)Introducimos otra variante, otra situacin normal.Queremos poder preguntarle a la empresa cuales son todos los empleados con ms de x aos. Es decir, no tenemos un valor nico y fijo como antes, de 18, sino que lo recibimos como parmetro.publicCollectiongetEmpleadosMayoresA(intanios){returnselect(this.getEmpleados(),newMayoresA(anios));}De nuevo, se ve ac que tenemos que pasarle todo el estado que necesite la condicin, como parmetro en la construccin. En este caso es un parmetro. Podra ser incluso una variable local.Aparece la Clase AnnimaDe lo anterior podemos concluir que la Condicin en general va a ser un objetito ms bien descartable, que lo uso para filtrar una coleccin en particular y luego lo descarto (ms an si tiene estado, no puedo reutilizar la condicin mayor a &lt;23&gt; si luego tengo que buscar los mayores a &lt;50&gt;).Adems, de que vamos a tener muchsimas clases implementaciones, segn cuntos criterios de filtrado tengamos en el sistema.Esto es porque en realidad lo que necesitaramos es expresar un pedacito de cdigo nada ms.Bien, como java no tiene bloques, para apalear un poco este problema, introduce la idea de clase annima interna (del ingls anonymous inner classes). La idea es que en el cuerpo de un mtodo pueda escribir una clase ah mismo, inline, es decir sin necesidad de hacerlo en otro archivo. Como voy a implementar con esto un pedacito de cdigo descartable, no hace falta que le ponga nombre a esta clase.Entonces, dirctamente instancio la interfaz (o clase abstracta), abro llaves, y ah mismo la implemento.Ejemplo:publicCollectiongetMayoresDe18(){CondicionmayoresA18=newCondicion(){@Overridepublicbooleancumple(Objectobj){return((Persona)obj).getEdad()&gt;18;}};returnselect(personas,mayoresA23);}Este ejemplo es equivalente al primero que hicimos. Ntese que estamos haciendovariable=La sintaxis esnewInterface(){//implementacindelainterface}Eso me da un objeto, que en este primer ejemplo lo asignamos a una variable local. Podramos incluso no usar la variable local y dirctamente crearla para pasarla por parmetro al select.publicCollectiongetMayoresDe18(){returnselect(personas,newCondicion(){@Overridepublicbooleancumple(Objectobj){return((Persona)obj).getEdad()&gt;18;}});}Fjense que es lo mismo, simplemente metimos todo el cdigo desde el new Cond hasta el cierre de llaves de la calse, en el lugar del parmetro.As, si lo miran con cario (mucho cario), se parece un poco a la implementacin con bloques.Ojo, las reglas son las mismas que cuando definimos una clase en otro archivo. Como que: nos fuerza a implementar todos los mtodos abstractos. podemos sobrescribir un mtodo (en caso de hacer una subclase annima de una clase abstracta). podemos llamar a super (pasa clase abstracta tambin). etc.Sin embargo, a diferencia de una clase normal tiene algunas particularidades.Acceso a la instancia contenedora (Clase.this)La clase annima adems de poder acceder a su estado interno y mandarle mensajes a los parmetros que recibe en mtodos, ve y puede tambin acceder al estado interno y mandarle mensajes a la instancia de la clase que la cre (es decir donde est el cdigo definido).Rehagamos el ejemplo de la empresapublicclassEmpresa{publicCollectiongetEmpleados(){returnselect(personas,newCondicion(){@Overridepublicbooleancumple(Objectobj){return((Persona)obj).getEmpleador()==Empresa.this;}});}}Ven que ac estamos necesitamos comparar el empleador de la persona con la nosotros mismos. El problema es que estamos teniendo cdigo dentro de una clase (annima de Condicion) que est dentro de otra clase (Empresa). Entonces, no existe un nico this. Tenemos dos. Como regla para toda clase annima this: se refiere al objeto de la clase annima, en nuestro caso sera la instancia de Condicion. ClaseContenedora.this: se refiere al objeto instancia de la clase contenedora de esta annima. En nuestro caso la Empresa.As podramos mandarle mensajes tambin...returnEmpresa.this.esExEmpleado((Persona)obj);...Donde esExEmpleado(Persona p) sera un mtodo de la Empresa.O tambin accederle a una variable de instancia...return((Personap)obj).getEmpleador().getNombre().equals(Empresa.this.nombre);...Acceso a variables locales (final)Existe una particularidad de la implementacin de Java, para recrear el ltimo caso en que usbamos un parmetro edad para fitrar.Si escribieramos eso as:publicCollectiongetMayoresA(intedad){returnselect(personas,newCondicion(){@Overridepublicbooleancumple(Objectobj){return((Persona)obj).getEdad()&gt;edad;}});}Tendrmos un error de compilacin al hacer &gt; edad, es decir al intentar acceder desde el cdigo de la clase annima al parmetro. Esto es porque la clase annima si bien tiene acceso al scope de variables del mtodo, solo puede acceder a aquellas variables que sean final, es decir que sean constantes, que no puedan cambiar. Esto es por una limitacin de java. La solucin sera agregar el modificador final al parmetropublicCollectiongetMayoresA(finalintedad){...Lo mismo sucede con referencias localespublicCollectiongetMayoresAlPromedioDeEdad(){finalintpromedioDeEdad=this.calcularPromedioDeEdad();returnselect(personas,newCondicion(){@Overridepublicbooleancumple(Objectobj){return((Persona)obj).getEdad()&gt;promedioDeEdad;}});}Ntese que la referencia local promedioDeEdad est declarada como final.Y si queremos cambiar el valor de la variable local (no puedo hacerla final) ??Bien, se puede resolver, sin embargo introduce burocracia. Para no cambiar el dominio vamos a tener que caer en un ejemplo de manejo de estructura.Supongamos que queremos obtener a un diccionario o Mapa con los empleados asociados a su edad expresada en decadas. Ej:20&gt;Juan(23),Jose(27),Maria(21)30&gt;Yesi(30),Nico(36)40&gt;Carlos(48)...Haramos una iteracin entre 20 y 70, por ejemplo, filtrando los empleados que tengan edad &gt;= i y edad &lt;= i + 9publicMap&lt;Integer, Collection&gt;getEmpleadosPorEdad(){Map&lt;Integer, Collection&gt;empleadosPorEdades=newHashMap&lt;Integer,Collection&gt;();for(inti=20;i&lt;=70;i+=10){CollectionempleadosEncontrados=select(this.getEmpleados(),newCondicion(){@Overridepublicbooleancumple(Objectobj){intedad=((Persona)obj).getEdad();returnedad&gt;=i&amp;&amp;edad&lt;=(i+9)}});empleadosPorEdades.put(i,empleadosEncontrados);}}Bien, esto no compilara, porque desde la clase annima estamos usando la variable local i, que no es final. Si procedemos a ponerle final en la declaracin, ahora no va a compilar el for en la parte del i+=10 porque no se puede modificar una variable final. Entonces, estamos en una encrucijada. La forma de resolverla, es mover la clase annima a otro mtodo, donde la i s la podemos declarar como final. Para esto podemos extraer el filtrado a otro mtodo, y desde este pasarle la i como parmetro.publicMap&lt;Integer, Collection&gt;getEmpleadosPorEdad(){Map&lt;Integer, Collection&gt;empleadosPorEdades=newHashMap&lt;Integer,Collection&gt;();for(inti=20;i&lt;=70;i+=10){CollectionempleadosEncontrados=this.getEmpleadosEnLaDecadaDel(i);empleadosPorEdades.put(i,empleadosEncontrados);}}Y el nuevo mtodo:publicCollectiongetEmpleadosEnLaDecadaDel(finalinti){returnselect(this.getEmpleados(),newCondicion(){@Overridepublicbooleancumple(Objectobj){intedad=((Persona)obj).getEdad();returnedad&gt;=i&amp;&amp;edad&lt;=(i+9)}});}Como ven el parmetro i nunca cambia en este mtodo, as que s podemos declararlo como final. Mientras que en el for puede seguir siendo no final." + +} , + +{ + +"title" : "Clases vs instancias", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/clases-vs-instancias.html", +"date" : "", +"content" : "En los lenguajes orientados a objetos que tienen clases (como Java, Xtend, Groovy, Scala, Smalltalk, Ruby, etc.) es frecuente como diseadores preguntarnos si un determinado requerimiento se puede resolver con instancias o con clases.Ejemplo: tenemos tareas en un proyecto, a cada tarea le corresponden distintos impuestos el impuesto A es un 3% del costo de la tarea el impuesto B representa un 2% del costo de la tarea el impuesto C es un 1,5% del costo de la tareaResolvemos el valor del impuesto Ametodovalor(Tareatarea)tarea.costo*0.03fin&lt;/code&gt;Y a continuacin el valor del impuesto Bmetodovalor(Tareatarea)tarea.costo*0.02fin&lt;/code&gt;Pero si analizamos con detenimiento veremos que los 3 impuestos comparten el mismo clculo: la nica diferencia es el % que se le aplica al costo de una tarea. No tiene sentido armar una jerarqua de clases para los impuestos: Impuesto Impuesto A, mtodo valor(Tarea) Impuesto B, mtodo valor(Tarea) Impuesto C, mtodo valor(Tarea) Es mucho ms conveniente generar una nica abstraccin impuesto que tenga el porcentaje como atributo:ClaseImpuestoatributoporcentajemetodovalor(Tareatarea)tarea.costo*porcentajefin&lt;/code&gt;Y no necesitamos tener las clases Impuesto A, B y C: si existieran, slo se diferenciarian en el valor que almacenan en el porcentaje al construirse.Conviene trabajar con clases cuando hay comportamiento diferencial entre ellos, por el contrario cuando no hay diferencias en el comportamiento es preferible modelar esa solucin con objetos. Una clase que no define comportamiento o atributos es sospechosa y como diseadores deberamos justificar una abstraccin de esta naturaleza.Si apareciera un Impuesto D, que se calcula como el mximo entre $ 400 y el 5% del costo de la tarea, entonces s tendra justificativo crear una nueva clase para modelar este impuesto, dado que el clculo es diferente." + +} , + +{ + +"title" : "Clases", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/clases.html", +"date" : "", +"content" : "Motivacin y ProblemaPor qu necesito clases? Porque tengo varios objetos sospechosamente parecidos. Es decir, El comportamiento de varios objetos es igual. Es decir, no solo entienden los mismos mensajes, sino que tienen los mismos mtodos (exactamente el mismo cdigo). sus atributos son los mismos, pero el estado interno es diferente. Es decir, si bien tienen los mismos atributos, stos pueden apunta a diferentes objetos. su identidad es diferente. Es decir, incluso si se comportan igual y se encuentran en el mismo estado, no son el mismo objeto.En conclusin, necesitamos una abstraccin donde pongamos el cdigo y los atributos en comn de todos stos objetos. sta abstraccin es la clase, y cada objeto que se comporte igual (aunque tenga diferente estado interno) va a ser una instancia de esa clase.Podemos pensar a las clases como Especies y a las instancias como individuos de esas especies Especie (Clase) Individuo (instancia) Leon simba nala mufasa Hiena shenzi banzai ed Jabal pumba Zuricata timon Cosas a recordar Todo objeto es siempre instancia de una y slo una clase. No se puede cambiar la clase de un objeto una vez creado. Los mtodos y atributos declarados en una clase son para sus instancias.Method LookupSi el cdigo est en la clase, entonces, Cmo responde ahora un objeto a un mensaje? Con el Method Lookup. El method lookup es el mecanismo por el cual un objeto va a buscar el mtodo correspondiente a su clase. (si no lo encuentra en su clase, no lo entiende). Revisar Herencia para conocer el Method Lookup completo.Alto! Quin soy yo?Si mi cdigo ahora no est en mi objeto, sino en una clase, Quin es self??selfapuntasiempreal objeto receptor del mensaje.En ste envo de mensaje:simba.rugi()Si el mtodo rugi() de la clase Leon usa self internamente, simba es self.De dnde salen las instancias?Si definimos una clase, por ejemplo Leon, y queremos obtener a simba que es una instancia de Leon para poder mandarle mensajes, necesitamos crear la instancia a partir de la clase Leon. O sea que la clase tiene un segundo rol importante, no sirve slo para definir el comportamiento y los atributos, tambin sirve para crear los objetos que luego usaremos en nuestro programa.Dependiendo del lenguaje, esto puede hacerse de formas distintas.En lenguajes en los cuales las clases son objetos, como es el caso de Smalltalk o Ruby por ejemplo, esto se hace mandndole un mensaje a la clase correspondiente. Por ejemplo:simba:=Leonnew.mufasa:=Leonnew.simbatuPapaEs:mufasa.En otros lenguajes, como en Wollok o Java, las clases no son objetos y para crear instancias se utilizan herramientas especficas para la construccin de objetos. Por ejemplo:varsimba=newLeon()varmufasa=newLeon()simba.tuPapaEs(mufasa)Es importante entender que en las lneas del estilo unaVar:=UnaClasenew. o varunaVar=newUnaClase() pasan dos cosas, en el orden que se indica: se crea un objeto instancia de la clase UnaClase. se hace que la variable unaVar haga referencia al objeto recin creado.Puede perfectamente instanciarse una clase y no asignar una variable en la misma lnea con el nuevo objeto, siempre depende de lo que se est tratando de hacer. Por ejemplo podra crearse un objeto dentro de un mtodo y retornarlo directamente, o crearlo para mandarle un mensaje directamente.Si una instancia no es referenciada desde ningn lado, la misma ya no podr ser usada, ya que nadie va a poder mandarle mensajes. Sin embargo no debemos preocuparnos por la memoria que ocupen estos objetos no olvidados, ya que ese trabajo es del Garbage Collector.ConclusinUna clase sirve de fbrica de objetos. Modela las abstracciones de mi dominio (los conceptos que nos interesan), permitindome definir el comportamiento y los atributos de las instancias.Dependiendo del lenguaje las clases pueden ser un objeto ms que entiende mensajes pensados para ellas (este es el caso de Smalltalk, ver Variables y mtodos de clase) o una construccin distinta del lenguaje que slo existe para declarar el comportamiento de los objetos y darnos una forma de obtener nuevas instancias mediante el uso de herramientas de instanciacin (no envos de mensajes) como sucede en Wollok.Lo importante de todo esto es que las clases no son construcciones centrales como s son los objetos, ya que impactan slo a la definicin y creacin de los mismo, pero para el uso general del sistema, trabajamos de la misma forma que si las clases no estuvieran ah. Es por eso que es en estos puntos en donde ms difieren los lenguajes existentes, sin embargo la idea de objeto - mensaje se mantiene." + +} , + +{ + +"title" : "Coeficiente de felicidad docente", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/coeficiente-de-felicidad-docente.html", +"date" : "", +"content" : "El Coeficiente de Felicidad Docente, a.k.a. CFD, mide la felicidad producida en una persona que se dedica a la enseanza en funcin de la respuesta obtenida de parte de sus pupilos.Diversos factores pueden hacer variar este ndice. Algunos ejemplos: Luego de machacar durante varias clases sobre la sintaxis de Smalltalk, resaltando que un envo de un mensaje SIEMPRE tiene que tener un objeto receptor, un ejercicio se entrega con una lnea que dice vola: 5. Al haber sido completamente ignorado el aviso del docente y omitirse el objeto receptor en esa lnea, el CFD se cae a pique. En un ejercicio en el que se pide resolver un problema X, un alumno logra combinar los conceptos vistos en clase para resolverlo. No contento con eso, considera que puede haber una mejor forma de resolver el problema porque su solucin no le parece elegante y consulta al docente para que este lo oriente. El CFD cotiza en alza, debido a que el docente puede detectar que lo transmitido en clase fue asimilado por el alumno y, adems, porque nota que el mismo intenta mejorar lo realizado y no slo zafar el ejercicio." + +} , + +{ + +"title" : "Comidas", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/comidas.html", +"date" : "", +"content" : "Salado Empanadas Relleno de carne Relleno Caprese Relleno Dale (las Sin Queso) Masa de pizza Fideos Palitos de queso Salsa Jack Daniels Bagna Cauda Locro Guiso de LentejasDulce Brownies Panqueques" + +} , + +{ + +"title" : "Como bajar y correr un ejemplo en wicket", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/como-bajar-y-correr-un-ejemplo-en-wicket.html", +"date" : "", +"content" : "Primer proyecto con Wicket Bajar alguno de los ejemplos, por ejemplo ste Importarlo como Maven ProjectIncorporar la app al web server Posicionarse en la solapa Servers: Window &gt; Show view &gt; Other Server Luego botn derecho sobre Server &gt; Add and Remove Pasar la aplicacin del container Available a Configured (seleccionarla y luego presionar el botn Add&gt;) Finish Reiniciar el servidor (botn derecho &gt; Restart in Debug o Restart)Acceder desde el browser a la direccionhttp://localhost:8080/aplicacion-web-en-cuestion/Links relacionados Temario Algoritmos III" + +} , + +{ + +"title" : "Como crear una subclase en squeak", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/como-crear-una-subclase-en-squeak.html", +"date" : "", +"content" : "Para crear una subclase hay dos formas:Forma A En un class browser System Browser ctrl-click (click derecho en Pharo) sobre la superclase, les abre un men contextual. Ah more-&gt;subclass template (en Pharo sin el more..). Les va a aparecer un texto parecido a este (en mi ejemplo tom como superclase a la clase Ave):Avesubclass:#NameOfSubclassinstanceVariableNames:''classVariableNames:''poolDictionaries:''category:'PDEP-EjemploGolondrinas' Reemplazar #NameOfSubclass por el nombre de la clase que quieran (ojo hay que dejar el #) Pueden agregar variables de instancia y de clase (entre comillas simples y separadas por espacios). Elegir la categora que queran, por defecto les va a aparecer la misma categora que la superclase (les conviene poner todas sus clases en una categora propia (o un varias categoras propias si quieren diferenciarlas de alguna manera). Si ponen un nombre de categora nuevo les va a crear la categora junto con la clase. Salvar (ctrl+s o ctrl+click, accept (*))Si ven bien los pasos 3-5 son para cualquier clase, la gran diferencia es que para crear una clase comn dice Object en lugar de Ave (es decir, todas nuestras clases son subclases de Object, salvo que yo le indique alguna otra ms especfica).Forma BUna forma que puede resultar ms sencilla es directamente copiar el texto que est arriba en la seccin de cdigo del Class Browser (eso reemplaza los puntos 1 y 2) y luego modificarlo y salvarlo (igual a los pasos 3-6).(Asegrense de borrar todo lo que haya en la seccin de cdigo antes, es decir, tiene que ser el nico texto en ese lugar, lo modifican y lo graban, voil). Una cosa que puede resultar difcil del squeak es que hay que usar siempre ctrl-click en lugar de lo que los usuarios windows estn acostumbrados como click derecho para configurar eso: Men Ppal -&gt; system preferences -&gt; preferences -&gt; escriben en el campito de texto swap y le tildan la opcion swap mouse buttons -&gt; save." + +} , + +{ + +"title" : "Como contribuir a la wiki", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/como-empezar.html", +"date" : "", +"content" : "IntroduccinEsta seccin describe brevemente la sintaxis de markdown que se usa en la wiki, adems de mostrar algunas cosas extras que componen a la wiki.Para hacer modificaciones simples con un articulo, basta con modificar desde github directamente el ariculo en cuestion.En caso de que se desee modificarLa carpeta wiki/articles contiene todos los articulos de la wiki, incluyendo esta seccin.RequerimientosPara testear localmente se necesitan los siguientes requerimientos previos. Ruby 2.5.0 Bundler yarn imagemagick pythonPara instalar las dependencias de ruby adicionales ejecutar:bundle installEste proyecto utiliza Jekyll, para levantar una instancia local una vez instaladas las dependencias habr que instalarlas dependencias adicionales mediante yarn:yarn installUna vez ya resueltas todas las dependencias se puede levantar el entorno mediante:jekyll s --iEsto arma un build local y una vez completado este proceso levanta localmente la instancia. De aqu en ms se podr hacer modificaciones localmente, y el servidor actualizar los cambios automticamente (es lo que hace el flag --i de incremental).Tener en cuenta que ante cualquier modificacin fuera de los artculos, como los plugins, se necesitar ejecutar un nuevo build de jekyll. (El servidor se levantar por default en localhost:4000)ModificandoUna vez levantado localmente nuestra instancia de jekyll con la wiki, podremos modificar los articulos que componenla wiki en s. Todos los articulos estn situados en ./wiki/articles, se pueden tener subdirectorios tambien, comopor ejemplo .wiki/articles/sub/Subpage.htmlTodos los articulos tienen que tener el header yml:---layout: articletitle: &lt;title&gt;---Despues de eso el formato de los articulos estan en markdown, todos los articulos deben tener el layout article El campo title es utilizado para Describir el titulo principal en el artculo.Syntaxis adicionalLinkeando artculosSe puede linkear un artculo de dos maneras Se puede utilizar el plugin link_article: &lt;a class="link article_link" href="/wiki/articles/como-empezar.html"&gt;como empezar&lt;/a&gt; O Hacerlo en markdown directamente:[The guide for newbies](/wiki/articles/como-empezar.html)Ambos enfoques generan el mismo html, solamente que en el primero se omite la extensin y los guiones medios (-).Embebiendo gistsSe puede embeber gists publicos de la siguiente manera:gist bossiernesto/97285bb96f1da185858af7de5cdee978Esto genera:#### Esto es un gist de pruebaBibliografaSe puede citar referencias mediante la sintaxis cite "nombre de cita"esto genera:(Burmako)Ahora existe un repositorio central de bibliografia en _bibliography/wikibiblio.bib. Todas las referencias deben estaranotadas con una sintaxis BibTex, la misma se puede obtener en algun sitio que nos brinde este tipo de formato como CiteSeerxSi se quiere mostrar toda la bibliografa del repositorio se tiene que usar la anotacin bibliographyFlanagan, David, and Yukihiro Matsumoto. The Ruby Programming Language. OReilly Media, 2008.Burmako, Eugene. Scala Macros: Let Our Powers Combine! On How Rich Syntax and Static Types Work with Metaprogramming.Ahora si queremos solo mostrar las bibliografa citada, utilizaremos la anotacin bibliography --citedBurmako, Eugene. Scala Macros: Let Our Powers Combine! On How Rich Syntax and Static Types Work with Metaprogramming.Para mayores referencias ver la siguiente seccinEmbeber markdown remotoSe puede embeber markdown en formato raw de un repositorio externo de la organizacion mediante la notacin` remote_markdown ` Cuando se utilice esta funcionalidad, verificar previamente que renderiza el link y el origen del mismo. Se recomienda que sea de un sitio como Github o Gitlab y que sea mediante una url por https.Embebiendo cdigoSe puede incluir cdigo con el triple backtrick. Esta wiki usa highlightjs para syntax highlighting. highlightjs tiene muchos esquemas y aqu hay algunos ejemplos.Hay que tener en cuenta que se debe configurar el idioma cuando se utiliza la sintaxis de triple &#92;`. El resaltado no funciona si no hay un idioma especificado.Ejemplo: class Bleh def a(b) b + 1 end endAlertasHay distinto tipos de alertas: secondary info success warning alertCada tipo de alerta tiene un color distinto, la sintaxis es la siguiente: "&lt;div data-alert class='alert-box secondary' tabindex='0' aria-live='assertive' role='alertdialog'&gt;" your text "&lt;/div&gt;"Donde &lt;kind&gt; puede ser secondary, info, success , warning oralert.Se agrega ahora el readme de jekyll-scholar con las referenciasJekyll-ScholarJekyll-Scholar is for all the academic bloggers out there. It is a set ofextensions to Jekyll, the awesome, blog aware, staticsite generator; it formats your bibliographies and reading lists for the weband gives your blog posts citation super-powers.Already using Jekyll-Scholar and interested to help out? Please get in touch with us if you would like to become a maintainer!Installation$ [sudo] gem install jekyll-scholarOr add it to your Gemfile:gem 'jekyll-scholar', group: :jekyll_pluginsGithub PagesNote that it is not possible to use this plugin with the default Github pages workflow.Github does not allow any but a few select plugins to run for security reasons,and Jekyll-Scholar is not among them.You will have to generate your site locally and push the results to the master resp. gh-pagesbranch of your site repository.You can keep sources, configuration and plugins in a separate branch; see e.g. herefor details.Alternatively, you can use a Github Actions called jekyll-action to deploy your site to Github PagesUsageInstall and setup a new Jekyll directory (see theJekyll-Wiki for detailedinstructions). To enable the Jekyll-Scholar add the following statementto a file in your plugin directory (e.g., to _plugins/ext.rb):require 'jekyll/scholar'Alternatively, add jekyll-scholar to your gem list in your Jekyllconfiguration:plugins: ['jekyll/scholar']ConfigurationIn your Jekyll configuration file you can adjust the Jekyll-Scholar settingsusing the scholar key. For example, the following sets the bibliography styleto modern-language-association.scholar: style: modern-language-associationThe table below describes some commonly used configuration options. For adescription of all options and their defaults, seedefaults.rb. Option Default Description style apa Indicates the style used for the bibliography and citations. You can use any style that ships with CiteProc-Ruby by name (e.g., apa, chicago-fullnote-bibliography) which is usually the filename as seen here without the .csl ending; note that you have to use dependent/style if you want to use one from that directory. Alternatively you can add a link to any CSL style (e.g., you could link to any of the styles available at the official CSL style repository). locale en Defines what language to use when formatting your references (this typically applies to localized terms, e.g., Eds. for editors in English). source ./_bibliography Indicates where your bibliographies are stored. bibliography references.bib Indicates the name of your default bibliography. For best results, please ensure that your bibliography is encoded as ASCII or UTF-8. A string that contains a * will be passed to Dir::glob, so **/*.bib{,tex} will find all files named *.bib and *.bibtex under source. allow_locale_overrides false When true, allows the language entry in the BibTex to override the locale setting for individual entries. When the language is missing it will revert back to locale. The language value should be encoded using the two-letter ISO 639-1 standard. Ex. English = en, Spanish = es. sort_by none Specifies if and how bibliography entries are sorted. Entries can be sorted on multiple fields, by using a list of keys, e.g. year,month. Ordering can be specified per sort level, e.g. order: descending,ascending will sort the years descending, but per year the months are ascending. If there are more sort keys than order directives, the last order entry is used for the remaining keys. order ascending Specifies order bibliography entries are sorted in. Can be ascending or descending. Ordering can be specified per sort level, e.g. descending,ascending will sort in descending on the first key then ascending order on the second key. If there are more sort keys than order directives, the last order entry is used for the remaining keys. group_by none Specifies how bibliography items are grouped. Grouping can be multi-level, e.g. type, year groups entries per publication type, and within those groups per year. group_order ascending Ordering for groups is specified in the same way as the sort order. Publication types specified with group key type, can be ordered by adding type_order to the configuration. For example, type_order: [article,techreport] lists journal articles before technical reports. Types not mentioned in type_order are considered smaller than types that are mentioned. Types can be merge in one group using the type_aliases setting. By default phdthesis and mastersthesis are grouped as thesis. By using, for example, type_aliases: { inproceedings: article}, journal and conference articles appear in a single group. The display names for entry types are specified with type_names. Names for common types are provided, but they can be extended or overridden. For example, the default name for article is Journal Articles, but it can be changed to Papers using type_names: { article: Papers }. bibtex_filters latex,smallcaps,superscript Configures which BibTeX-Ruby formatting filters values of entries should be passed through. The default latex filter converts LaTeX character escapes into unicode, smallcaps converts the &#92;textsc command into a HTML &lt;font style=&#92;"font-variant: small-caps&#92;"&gt; tag, and superscript which converts the &#92;textsuperscript command into a HTML &lt;sup&gt; tag. raw_bibtex_filters ` ` Configures which BibTeX-Ruby formatting filters the raw BiBTeX entry (i.e. that available through {{ entry.bibtex }}) should be passed through. This can be used to e.g. strip excess newlines by using the linebreaks filter. BibliographiesOnce you have loaded Jekyll-Scholar, all files with the extension .bib or.bibtex will be converted when you run Jekyll (dont forget to add a YAMLheader to the files); the file can contain regular HTML or Markdown andBibTeX entries; the latter will be formatted by Jekyll-Scholar according tothe citation style and language defined in your configuration file.For example, if you had a file bibliography.bib in your root directory:------References==========@book{ruby, title = {The Ruby Programming Language}, author = {Flanagan, David and Matsumoto, Yukihiro}, year = {2008}, publisher = {O'Reilly Media}}It would be converted to bibliography.html with the following content:&lt;h1 id='references'&gt;References&lt;/h1&gt;&lt;p&gt;Flanagan, D., &amp;#38; Matsumoto, Y. (2008). &lt;i&gt;The Ruby Programming Language&lt;/i&gt;. O&amp;#8217;Reilly Media.&lt;/p&gt;This makes it very easy for you to add your bibliography to your Jekyll-poweredblog or website.If you are using other converters to generate your site, dont worry, you canstill generate bibliographies using the bibliography tag. In your siteor blog post, simply call:{% bibliography %}This will generate your default bibliography; if you use multiple, you canalso pass in a name to tell Jekyll-Scholar which bibliography it should render.Lets say you have two bibliographies stored in _bibliography/books.bib and_bibliography/papers.bib; you can include the bibliographies on your siteby respectively calling {% bibliography --file books %} and{% bibliography --file papers %}. For example, you could have a file references.mdwith several reference lists:---title: My References---{{ page.title }}================The default Bibliography------------------------{% bibliography %}Secondary References--------------------{% bibliography --file secondary %}Finally, the bibliography tag supports an optional filter parameter. Thisfilter takes precedence over the global filter defined in your configuration.{% bibliography --query @*[year=2013] %}The example above would print a bibliography of all entires published inthe year 2013. Of course you can also combine the file and filter parameterslike this:{% bibliography -f secondary -q @*[year=2013] %}This would print the publications from 2013 of the bibliography at_bibliography/secondary.bib.For more details about filters, see the corresponding section below orconsult the BibTeX-Rubydocumentation.If you need to limit the number of entries in your bibliography, you canuse the --max option:{% bibliography --max 5 %}This would generate a bibliography containing only the first 5 entriesof your bibliography (after query filters and sort options have beenapplied). Limiting entries is disabled if grouping is active.Return number of publications in bibliographyThe bibliography_count returns the number of items that would berendered in a bibliography. This tag accepts the same parameters as thebibliography tag.{% bibliography_count -f references --query @book[year &lt;=2000] %}See #186for further examples.Bibliography TemplateYour bibliography is always rendered as an ordered list. Additionally,each reference is wrapped in an HTML tag (span by default but you canchange this using the reference_tagname setting) with the cite keyas id. The reference string itself is governed by the rules in yourCSL style but you can also customize the main template a little bit.By default, the template is {{reference}} this renders only thereference tag. The template uses Liquid to render and, inaddition to the reference, exposes the cite-key (as key), theentrys type, the index in the bibliography, and the link tofile repository as link. Thus, you couldcustomize the template in your configuration as follows:scholar: bibliography_template: &lt;abbr&gt;[{{key}}]&lt;/abbr&gt;{{reference}}This would be processed into something like:&lt;li&gt;&lt;abbr&gt;[ruby]&lt;/abbr&gt;&lt;span id="ruby"&gt;Matsumoto, Y. (2008). &lt;i&gt;The Ruby Programming Language&lt;/i&gt;. O&amp;#8217;Reilly Media.&lt;/span&gt;&lt;/li&gt;If you have more complex requirements, it quickly becomes tedious tohave the template inside the configuration; for this reason, you canalso put the bibliography template into your layouts directory. Jekyll-Scholarwill load this template if the option set in your configuration matchesan existing layout (without the file extension). That is to say, if you set:scholar: bibliography_template: bibAnd there is a file _layouts/bib.html (or with another extension) thecontents of this file will be used as the template. Please note that it isimportant for this file to contain the YAML front matter! For example, thiswould be a more complex template file:------{{ reference }}{% if entry.abstract %}&lt;p&gt;{{ entry.abstract }}&lt;/p&gt;{% endif %}&lt;pre&gt;{{ entry.bibtex }}&lt;/pre&gt;You can also override the default bibliography template, by passing the--template or -T option parameter to the bibliography tag.CitationsIf you want to reference books or papers from your bibliography in your blogposts, Jekyll-Scholar can help you, too. Simply use the cite tag withthe appropriate key of the item you want to cite and Jekyll-Scholar willcreate a formatted citation reference for you. For a quick example, takefollowing blog post:---layout: defaulttitle: A Blogging Scholar---{{ page.title }}================Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod temporincididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quisnostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Duis 'aute irure dolor in reprehenderit in voluptate' {% cite derrida:purveyor %}velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecatcupidatat non proident, 'sunt in culpa qui officia deserunt mollit anim id estlaborum' {% cite rabinowitz %}.Duis 'aute irure dolor in reprehenderit in voluptate' {% cite breton:surrealism %}velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecatcupidatat non proident, 'sunt in culpa qui officia deserunt mollit anim id estlaborum' {% cite rainey %}.References----------{% bibliography %}Note that this will print your entire bibliography in the Reference section.If you would like to include only those entries you cited on the page, passthe cited option to the bibliography tag:{% bibliography --cited %}By default, the --cited option will still sort your bibliography if you setthe sort option. Especially for styles using citation numbers, this is usuallynot the desired behaviour. In such cases you can use --cited_in_order insteadof --cited and your bibliography will contain all cited items in the orderthey were cited on the page.For longer quotes, Jekyll-Scholar provides a quote tag:{% quote derrida:purveyor %}Lorem ipsum dolor sit amet, consectetur adipisicing elit,sed do eiusmod tempor.Lorem ipsum dolor sit amet, consectetur adipisicing.{% endquote %}For example, this could be rendered as:&lt;blockquote&gt; &lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit,&lt;br/&gt; sed do eiusmod tempor.&lt;/p&gt; &lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing.&lt;/p&gt; &lt;cite&gt; &lt;a href="#derrida:purveyor"&gt;(Derrida, 1975)&lt;/a&gt; &lt;/cite&gt;&lt;/blockquote&gt;Multiple citationYou can cite multiple items in a single citation by referencing all idsof the items you wish to quote separated by spaces. For example,{% cite ruby microscope %} would produce a cite tag like:&lt;a href="#ruby"&gt;(Flanagan &amp;amp; Matsumoto 2008; Shaughnessy 2013)&lt;/a&gt;Citations when theres more than one bibliographyLets return to the example above where you have two bibliographies storedin _bibliography/books.bib and _bibliography/papers.bib. We also musthave the main bibliography, e.g., _bibliography/references.bib. As weknow from above, its possible to use bibliographies other than the mainbibliography by calling {% bibliography --file books %} or{% bibliography --file papers %}.Though what if we want to cite an article thats not in the main bibliography?We use the same approach as above; to cite an article in the books.bibbibliography, we simply call {% cite ruby --file books %}Suppressing author namesSometimes you want to suppress author names in a citation, because thename has already been mentioned in your text; for such cases Jekyll-Scholarprovides the --suppress_author option (short form: -A):...as Matz explains {% cite ruby -A -l 42 %} would produce somethinglike: ...as Matz explains (2008, p. 42).Page numbers and locatorsIf you would like to add page numbers or similar locators to your citation,use the -l or --locator option. For example, {% cite ruby --locator 23-5 %} wouldproduce a citation like (Matsumoto, 2008, pp. 23-5).When quoting multiple items (see above) you can add multiple locators afterthe list of ids. For example, {% cite ruby microscope -l 2 -l 24 &amp; 32 %}.Page is the default locator, however, you can indicate the type of locatorby adding a -L or --label option (one for each locator) for instance,{% cite ruby microscope --label chapter --locator 3 -L figure -l 24 &amp; 32 %}produces something like: (Matsumoto, 2008, chap. 3; Shaughnessy, 2013, figs. 24 &amp; 32).Displaying formatted referencesIf you want to display the full formatted reference entry, you can use thereference tag. For example, given the following Bibtex entry,@book{ruby, title = {The Ruby Programming Language}, author = {Flanagan, David and Matsumoto, Yukihiro}, year = {2008}, publisher = {O'Reilly Media}}using {% reference ruby %} anywhere in your page, it will printFlanagan, D., &amp; Matsumoto, Y. (2008). The Ruby Programming Language..OReilly Media (the exact result depends on your formatting style).The reference tag accepts the same file/-f parameter as the bibliographytag. This can be handy if you want to use a special BibTeX file as input fora specific page. As an example, the tag{% reference ruby --file /home/foo/bar.bib %}will attempt to read the key ruby from file /home/foo/bar.bib. It will notfallback to the default BibTeX file.Citation pointing to another page in your siteIn some cases, you might want your citation to link to another page on your cite (ex. a separate works cited page). As a solution, add a relative path to your scholar configurations: scholar: relative: "/relative/path/file.html"Multiple bibliographies within one document (like multibib.sty)When you have multiple {% bibliography %} sections in one file,Jekyll-Scholar will generate several lists containing the samepublications that have the same id attributes. As a result, when youcite a reference the link to an id attribute cannot be resolveduniquely. Your browser will always take you take you to the firstoccurrence of the id. Moreover, valid HTML requires unique idattributes. This scenario may happen, for example, if you cite thesame reference in different blog posts, and all of these posts areshown in one html document.As a solution, Jekyll-Scholar provides the --prefix tag. In yourfirst post you might cite as---title: Post 1---Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod temporincididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quisnostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Duis 'aute irure dolor in reprehenderit in voluptate'{% cite derrida:purveyor --prefix post1 %} velit esse cillumdolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatatnon proident, 'sunt in culpa qui officia deserunt mollit anim idest laborum' {% cite rabinowitz --prefix post1 %}.References----------{% bibliography --cited --prefix post1 %}For the second blog post you would cite as follows:---title: Post 2---Duis 'aute irure dolor in reprehenderit in voluptate'{% cite rabinowitz --prefix post2 %} velit esse cillumdolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatatnon proident, 'sunt in culpa qui officia deserunt mollit anim idest laborum' {% cite rainey --prefix post2 %}.References----------{% bibliography --cited --prefix post2 %}Even though both posts cite rabinowitz, both citations will beassigned unique identifiers linking to the respective referencessection, although both posts will be rendered into a single HTMLdocument.Add a custom class for the citation referenceBy default Jekyll Scholar generate a link with a class:&lt;a href="#ruby" class="citation"&gt;(Derrida, 1975)&lt;/a&gt;You can custom this class in your configuration:scholar: cite_class: citationFile RepositoriesFile repository support was added to Jekyll-Scholar starting at version2.0. Currently, if you have a folder in your site that contains PDF orPostscript files of your papers, you can use the configuration optionrepository to indicate this directory. When generating bibliographies,Jekyll-Scholar will look in that folder to see if it contains a filenamematching each entrys BibTeX key: if it does, the path to that filewill be exposed to the bibliography template as the link property.Since version 4.1.0 repositories are not limited to PDF and PS files.These files are mapped to the links property in your bibliographytemplate. Here is an example of template that utilizes this featureto link to supporting material in a ZIP archive:{{ reference }} [&lt;a href="{{links.zip}}"&gt;Supporting Materials&lt;/a&gt;]Since version 5.9.0, Jekyll-Scholar matches files which begin with a BibTeX keyand are immediately followed by a delimiter (default: .). All text proceedingthe delimiter is treated as the file extension. For example, if two files namedkey.pdf and key.slides.pdf are found, {{links.pdf}} and{{links['slides.pdf']}} will both be populated. You can use the configurationoption repository_file_delimiter to change the default delimiter.Detail PagesIf your layouts directory contains a layout file for bibliography details(the details_layout configuration options), Jekyll-Scholar will generatea details page for each entry in you main bibliography. That is to say, ifyour bibliography contains the following entry:@book{ruby, title = {The Ruby Programming Language}, author = {Flanagan, David and Matsumoto, Yukihiro}, year = {2008}, publisher = {O'Reilly Media}}Then a page bibliography/ruby.html will be generated according to yourdetails page layout. In the layout file, you have access to all fieldsof your BibTeX entry. Here is an example of a details page layout:------&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt; &lt;h1&gt;{{ page.entry.title }}&lt;/h1&gt; &lt;h2&gt;{{ page.entry.author }}&lt;/h2&gt; &lt;p&gt;{{ page.entry.abstract }}&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;When Jekyll-Scholar generates detail pages, it also adds links to eachentrys detail page to the generated bibliography. You can alter thename of the link via the details_link configuration option.Jekyll-Scholar also provides a Liquid tag for conveniently adding linksto individual detail pages. For example, if you would like to add a simplelink to one of the items in your bibliography on a page or in a blog postyou can use the cite_details tag to generate the link. For this to work,you need to pass the BibTeX key of the element you want to reference tothe tag and, optionally, provide a text for the link (the default textcan be set via the details_link configuration option).Duis 'aute irure dolor in reprehenderit in voluptate' velit esse cillumdolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat nonproident {% cite_details key --text Click Here For More Details %}.Alternatively, you can use the details_link tag to get just the URL to a details page. This can be used to link to details pages in markdown the same way you would link to a blog post with Jekylls link tag.[See our blog post]({% link _posts/2020-01-01-research-post.md %}) or [find more details]({% details_link key %}).Bibliography FiltersBy default, Jekyll-Scholar includes all entries in you main BibTeX filewhen generating bibliographies. If you want to include only those entriesmatching certain criteria, you can do so by adjusting the queryconfiguration option. For example:query: "@book" #=&gt; includes only booksquery: "@article[year&gt;=2003]" #=&gt; includes only articles published 2003 or laterquery: "@*[url]" #=&gt; includes all entries with a url fieldquery: "@*[status!=review]" #=&gt; includes all entries whose status field is not set to 'review'query: "@book[year &lt;= 1900 &amp;&amp; author ^= Poe]" #=&gt; Books published before 1900 where the author matches /Poe/query: "!@book" #=&gt; includes all entries with a type other than bookPlease note that some of these queries require BibTeX-Ruby 2.3.0 orlater versions. You can also overwrite the configurations query parameterin each bibliography tag individually as described above.ContributingThe Jekyll-Scholar source code ishosted on GitHub.You can check out a copy of the latest code using Git:$ git clone https://github.com/inukshuk/jekyll-scholar.gitTo use this lasted version instead of the one provide by RubyGems,just add the line$:.unshift '/full/path/to/the/repository/lib'to your _plugins/ext.rb before requiring jekyll/scholar, where/full/path/to/the/repository is the path to your local versionof Jekyll-Scholar.When contributing to Jekyll-Scholar, please make sure to installall dependencies and run the cucumber features:$ bundle install$ rakeIf youve found a bug or have a question, please open an issue on theJekyll-Scholar issue tracker.Or, for extra credit, clone the Jekyll-Scholar repository, write a failingexample, fix the bug and submit a pull request.Additionally, if we merged at least one of your pull request you will getwrite permissions to the repository if you want them.LicenseJekyll-Scholar is distributed under the same license as Jekyll.Copyright (c) 2011-2015 Sylvester KeilPermission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the Software), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE." + +} , + +{ + +"title" : "Como hacer para que de un objeto muestre lo que yo quiero", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/como-hacer-para-que-de-un-objeto-muestre-lo-que-yo-quiero.html", +"date" : "", +"content" : "antes que nada, otra forma de saber si lo que me devuelve es lo que quieroSupongamos que tengo las clases Golondrina y Lugar, que entienden estos mensajes Golondrina: energia (un nmero), dondeEsta (un lugar), jefaDeBandada (otra golondrina) Lugar: kmEnRuta (un nmero)En un workspace tengo estopepita:=Golondrinanew.luciana:=Golondrinanew.buenosAires:=Lugarnew.pepitainitialize.lucianainitialize.buenosAiresinitialize.buenosAireskmEnRuta:10.pepitajefaDeBandada:luciana."ledigoapepitaquelajefadesubandadaesluciana"pepitaubicacionInicial:buenosAires."despusdeesto,pepitaestenbuenosaires"Si despus de todo esto en el workspace pongopepitaenergiay le doy display it, me va a mostrar un nmero, p.ej. 0. Ahora, si pongopepitajefaDeBandaday le doy display it, no me va a mostrar luciana que es tal vez lo que esperaba, sino a Golondrina. Parecido si pruebo conpepitadondeEstame va a decir a Lugar.Si tengo 5 golondrinas en mi workspace, cmo s que la que me devuelve cuando le pido la jefa de bandada a pepita es luciana y no otra? luciana es el nombre de la variable que apunta a luciana dentro del workspace, entonces dentro del workspace puedo usar ese nombre. Sabiendo esto, una fcil es preguntar si lo que me devuelve pepita jefaDeBandada es luciana, o seapepitajefaDeBandada=lucianaahora las respuestas van a ser true o false.ahora s, el misterio de a GolondrinaPonele que ests pensando todo bien, pero lo que quiero es que no me ponga a Golondrina. Adelante.Empecemos por entender por qu pone a Golondrina.Ya vimos que los objetos no tienen nombre propio, los que tienen nombre son las variables que hacen referencia al objeto. luciana es la variable del workspace que apunta a una golondrina, la golondrina no tiene nombre propio.Entonces, cuando pinto una expresin y le doy display it, qu me muestra? Me muestra un String que representa al objeto resultado de la expresin. Para los objetos bsicos (nmeros, String, booleanos), ese String es lo que uno espera. Para las instancias de las clases que creamos nosotros, es en principio el nombre de la clase antecedido de a (o an si el nombre de la clase empieza en vocal). Por eso a Golondrina.Si entendimos esto, la pregunta que sigue es puedo hacer que el String que representa a (p.ej.) las golondrinas no sea a Golondrina sino otra cosa que yo quiera.S, y no es muy difcil.printOn:Lo que hay que hacer es definir el mtodoprintOn:en la clase cuyas instancias queremos que se muestren distinto (en el ejemplo, Golondrina y Lugar).Lo que viene como parmetro es un Stream, que es una tira de caracteres. En el mtodo tens que agregar el String que vos quieras a la tira. Todos los objetos son polimrficos respecto del printOn:, para las clases que no tienen una definicin explcita, Smalltalk provee la que muestra el nombre de la clase.El display it lo que hace es: crear un Stream, pedirle al resultado de la expresin printOn: sobre ese Stream, tomar el String generado, mostrar eso.Los Stream entienden estos mensajes: nextPutAll: unString , agrega unString a la tira cr , agrega un salto de lnea a la tiraTengamos tambin en cuenta que los String entienden el mensaje coma (,) que concatena, probar p.ej.'hola','mundo'Ms sobre Strings en el apunte sobre objetos bsicos en www.pdep.com.ar .Ya vimos que los objetos bsicos se muestran bien, y ahora sabemos que eso es porque al decirle printOn: devuelven un String feliz. P.ej. el 42 agrega el String 42, por eso es que cuando el resultado de una operacin es 42 y le pido display it de esa operacin, me muestra 42 y no a Number. Esto lo podemos usar, si dentro de lo que quiero mostrar hay p.ej. un nmero, entonces al nmero le puedo decir printOn: sobre el mismo Stream que me pasaron a m.Hagamos que los lugares y golondrinas se muestren bien#LugarprintOn:unStreamunStreamnextPutAll:'lugarenkm'.selfkmEnRutaprintOn:unStreamla segunda lnea de cdigo agrega el String correspondiente al nmero en el mismo Stream que le lleg al lugar, entonces el resultado va a ser p.ej. lugar en km 10.#GolondrinaprintOn:unStreamunStreamnextPutAll:'golondrinaconenerga'.selfenergiaprintOn:unStream.unStreamnextPutAll:'yqueesten('.selfdondeEstaprintOn:unStream.unStreamnextPutAll:')'.ac us el mismo truco para la energa (un nmero) y para el lugar, para el que va a usar el printOn: de lugar que definimos recin. Entonces el resultado va a ser golondrina con energa 0 y que est en (lugar en km 10).ok, pero quiero que me diga pepitaBueno, para eso el objeto tiene que conocer al String pepita. P.ej. que las golondrinas tengan nombre. Cmo? Bueno, eso ya lo deberan poder hacer ustedes ;-)." + +} , + +{ + +"title" : "Como hacer predicados de orden superior", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/como-hacer-predicados-de-orden-superior.html", +"date" : "", +"content" : "Recordemos los predicados de orden superior que vimos hasta el momento, esos predicados que relacionan predicados: not/1 findall/3 forall/2Eso es todo lo que hay? No, por supuesto que no. Existen muchos otros predicados de orden superior pre-construidos (built-in), pero esta base nos alcanza para lo que queremos ver en la materia. Pero lo ms interesante es que podemos construir nuestros propios predicados de orden superior, sin embargo vamos a ver que no es tan natural como s era en Haskell.call / 1El predicado call/1 nos permite evaluar un predicado pasado por parmetro. Retomando uno de nuestros primeros ejemplos, veamos cmo se usara:?-call(padre(Padre,Hijo)).Padre=homeroHijo=bart;...Pero eso no aporta mucho respecto de hacerlo en forma directa:?-padre(Padre,Hijo).Padre=homeroHijo=bart;...Se supone que slo tiene sentido usar esto si no sabemos qu consulta es la que nos van a pasar por parmetro y usamos el call/1 para definir algo ms genrico. Veamos otra variante, entonces, que puede resultarnos ms interesante y til para lo que s podemos llegar a usar.call / _El predicado call/_ tambin nos permite evaluar un predicado pasado por parmetro, pero separando los parmetros que el mismo recibe:?-call(padre,Padre,Hijo).Padre=homeroHijo=bart;...O tambin:?-call(padre(homero),Hijo).Hijo=bart;...Momento, momento entonces, cul es la aridad de call/_? El predicado call/_ no tiene definida una aridad fija. Puede tener desde 1 (la versin que vimos antes) hasta N + 1, siendo N la aridad del predicado que se recibe como primer parmetro.Usando este predicado podemos hacer cosas equivalentes (no iguales!) a las que hacamos con orden superior en Haskell. Juguemos un poco con esto: implementemos map y filter.Creando nuestros propios predicados de orden superiorel viejo y querido filterLa cuestin de los parmetros es igual a la anterior: vamos a necesitar uno ms que lo que tena filter en Haskell para unificar la lista resultante. Hagamos tambin dos versiones.Versin recursiva:filterRecursivo(_,[],[]).filterRecursivo(Pred,[X|Xs],[X|Ys]):-call(Pred,X),filterRecursivo(Pred,Xs,Ys).filterRecursivo(Pred,[X|Xs],Ys):-not(call(Pred,X)),filterRecursivo(Pred,Xs,Ys).Versin no recursiva:filterNoRecursivo(Pred,ListaOrigen,ListaResultante):-findall(X,(member(X,ListaOrigen),call(Pred,X)),ListaResultante).Ejemplos de consulta:?-filterRecursivo(padre(homero),[herbert,lisa,maggie,homero,bart],ListaFiltrada).ListaFiltrada=[lisa,maggie,bart];No?-filterNoRecursivo(padre(homero),[herbert,lisa,maggie,homero,bart],ListaFiltrada).ListaFiltrada=[lisa,maggie,bart];NoBuensimo :D Este predicado tambin existe como built-in y, como el ttulo lo dice, es include/3.el viejo y querido mapEmpecemos por lo bsico cuntos parmetros tena la funcin map?&gt;mapflistaTena dos parmetros, una funcin de transformacin f y una lista, y la funcin era aplicable a cada elemento de la lista.Entonces, cuntos argumentos va a tener nuestra relacin maplist? Vamos a tener el predicado de transformacin y la lista, por supuesto. Pero tambin necesitamos un argumento ms para unificarlo con la lista resultante del mapeo. Tenemos tambin que considerar las cosas que relaciona el predicado: un elemento de la lista original con uno de la lista resultante.?-map(Predicado,ListaOriginal,ListaResultante).Ejemplo de uso:?-map(padre,[homero,abe],Hijos).Hijos=[[bart,lisa,maggie],[homero,herbert]]Ok, pensemos cmo lo podramos implementar para que haga lo que queremos?Versin 1 con recursividadmapRecursivo(_,[],[]).mapRecursivo(Pred,[X|Xs],[Y|Ys]):-call(Pred,X,Y),mapRecursivo(Pred,Xs,Ys).Ejemplos de consulta:?-mapRecursivo(padre,[homero,abe],Hijos).Hijos=[bart,homero];Hijos=[bart,herbert];Hijos=[lisa,homero];Hijos=[lisa,herbert];Hijos=[maggie,homero];Hijos=[maggie,herbert];NoOk esto no hace lo que queremos, vemos que vamos a tener mltiples respuestas donde para cada padre me mappea con un nico hijo de ese padre. Pensndolo desde un punto de vista genrico, ms all del dominio particular, nuestra primer implementacin nos da N respuestas con todas las combinaciones posibles de mapeo, pero siempre con mapeos 1 a 1 para cada elemento de la lista original. Qu ms se nos ocurre?Versin 2 con findall Tambin podramos hacer una versin no recursiva:mapNoRecursivo(Pred,ListaOriginal,ListaResultante):-findall(Y,(member(X,ListaOriginal),call(Pred,X,Y)),ListaResultante).Ejemplos de consulta:?-mapNoRecursivo(padre,[homero,abe],Hijos).Hijos=[bart,lisa,maggie,homero,herbert];NoPara nuestra implementacin no recursiva la respuesta es nica, pero estn en la misma lista los hijos de todos y segn nuestro ejemplo de uso esperado que dijimos al principio queramos que nos de una lista de listas, sino no podemos distinguir los que son hijos de homero respecto a los de abe.Las dos implementaciones que realizamos sin embargo funcionaran correctamente con relaciones que cumplan con unicidad (con lo cual estaramos ms cerca del mundo funcional, no siempre queremos esto, depende del problema). Si modelramos la relacin hijosDe/2 como:hijosDe(Padre,Hijos):-findall(Hijo,padre(Padre,Hijo),Hijos).Podramos hacer la siguiente consulta?-mapNoRecursivo(hijosDe,[homero,abe],Hijos).Hijos=[[bart,lisa,maggie],[homero,herbert]]Y el resultado sera idntico al de nuestro mapRecursivo.Y cul es el que est bien? La respuesta es depende. Si buscamos mltiples respuestas con relaciones 1 a 1 vamos a querer la primera, si buscamos una nica respuesta que englobe todas las respuestas posibles vamos a querer la segunda, y si queremos que sea 1 a 1 con una nica respuesta tenemos que asegurarnos de que nuestro dominio est modelado de forma acorde, incluso podramos tener una tercer versin como esta:Versin 3 con recursividad y findallmapListaDeListas(_,[],[]).mapListaDeListas(Pred,[X|Xs],[Y|Ys]):-findall(Z,call(Pred,X,Z),Y),mapListaDeListas(Pred,Xs,Ys).Esta consulta va a hacer lo que queramos originalmente, pero siempre nos va a dar una lista de listas y capaz no queremos eso?-mapListaDeListas(padre,[homero,abe],Hijos).Hijos=[[bart,lisa,maggie],[homero,herbert]]Ya que estamos en lgico, pensemos qu otras consultas podramos querer hacer:?-mapRecursivo(padre,Padres,[bart,lisa,maggie]).Padres=[homero,homero,homero];NoNuestra primer versin recursiva es inversible para el segundo o el tercer argumento (aunque no ambos simultneamente). Si probamos lo mismo con nuestra versin no recursiva, nos vamos a encontrar con un problema ya que en la implementacin estamos usando member/2 con la primera lista, y member/2 no es inversible para la lista.Lgicamente ninguna versin ser inversible respecto al primer argumento, ya que necesita saber qu predicado quiere consultar en el call.Bueno, la versin built-in de map en SWI-Prolog es maplist/3, y se comporta como nuestra versin recursiva.Cmo seguimos?Otro predicado de orden superior muy til es mejorSegun/3 que relaciona un predicado de aridad 2 a invocar, una lista y al valor que maximiza el segundo argumento del predicado en cuestin. Se animan a resolverlo?" + +} , + +{ + +"title" : "Composicion oop", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/composicion--oop-.html", +"date" : "", +"content" : "Supongamos que queremos modelar el comportamiento de personas a la hora de pagar la cuenta despus de una comida en un restaurant. Los clientes pagan lo que consumen ms la propina, que depende de su humor. Sabemos que la gente feliz deja de propina 25% de lo que sali la comida, la gente enojada no deja nada y los que estn de un humor indiferente dejan lo que tienen en el bolsillo.Queremos que un cliente nos pueda decir cunto paga en total (propina + lo que consumi) dado el importe de la comida consumida, y adems debe ser posible para una persona cambiar de humor a lo largo de la ejecucin del programa.Sera posible resolver toda esta lgica (y la que est por venir ms adelante) con muchos ifs en el cliente, pero es posible modelarlo de otra forma: los diferentes humores del cliente podran ser otros objetos separados que le ayuden a saber cunta propina poner, y por su puesto ser polimrficos para que el cliente pueda delegar en ellos esta funcionalidad sin importar cul sea su humor actual (objeto al cual referencia con algn atributo propio, como ser humor).Wollokclass Cliente { var property humor method cuantoPaga(importeTotal){ return importeTotal+self.cuantoDePropina(importeTotal) } methodcuantoDePropina(importeTotal){ return humor.cuantoDePropina(importeTotal) }} class Feliz { method cuantoDePropina(importeTotal){ return importeTotal*1.25 }class Enojado { method cuantoDePropina(importeTotal){ return 0 }}class Indiferente { var property plataDelBolsillo methodcuantoDePropina(importeTotal) return plataDelBolsillo }}Nota: en este ejemplo se ubic la variable plataDelBolsillo en la estrategia Indiferente. Esto implica que cada vez que el cliente cambie de humor a indiferente, hay que indicarle cunta plata en el bolsillo tiene.Otra opcin podra haber sido poner la plataDelBolsillo en el cliente y para que la estrategia Indiferente resuelva cunto tiene que devolver al recibir el mensaje cuantoDePropina hay dos opciones: Que la instancia del objeto Indiferente conozca al Cliente y le pida su plataDelBolsillo Que el cliente se pase por parmetro al pedirle a la estrategia cunta propina pone, modificando el mtodo para recibir dos parmetros, por ejemplo:Wollokclass Cliente { methodcuantoDePropina(importeTotal){ return humor.cuantoDePropinaPara(importeTotal,self) }}Ante la necesidad de poder cambiar el humor de la persona, separamos a la Persona (que intuitivamente iba a ser un concepto entero abarcando a su estado de humor) de su Humor en un concepto aparte. Los objetos Humor deben ser polimrficos para la persona, ya que debo poder intercambiar los distintos humores y la persona debera hablarle de la misma forma a cualquiera.Entonces en vez de tener un objeto que resuelve todo el problema tenemos un objeto que conoce a otros objetos polimrficos para resolver el problema mediante la colaboracin. Con esta solucin, el flujo del programa ya no se encuentra definido por los ifs y objetos bsicos sino por la configuracin del cliente y el uso de polimorfismo.Es importante notar que no sera vlido modelar una solucin a este problema basada en herencia teniendo personas felices, indiferentes y enojadas, ya que una vez que la persona es instanciada como feliz no es posible cambiarla a indiferente o enojada, ya que implicara cambiar su clase que no se puede hacer.Entonces, la composicin en objetos es simplemente una relacin de conocimiento entre dos objetos (por ejemplo, el cliente conoce a su humor) donde el objeto conocido puede cambiarse por otro que sea polimrfico para el que los conoce.Otro ejemplo podra ser el de las colecciones con un algoritmo de ordenamiento elegido por el usuario (SortedCollection en Smalltalk), donde la coleccin delega en otro objeto que modela el algoritmo de ordenamiento a usar sobre sus elementos.Cambiando herencia por composicinEl uso de composicin en ocasiones es una solucin muy elegante para problemas aparejados por el concepto de Herencia, que pueden verse en el siguiente ejemplo tomado de un final de Paradigmas de Programacin: El siguiente texto representa parte del relevamiento realizado en una cadena de venta de electrodomsticos: Los vendedores pueden ser especialistas o de saln. Los especialistas atienden detrs de mostrador y cobran un premio de 100 pesos por cada venta. Los vendedores de saln cobran un premio que se indica para cada vendedor. Avanzando en el relevamiento, nos dicen lo siguiente: Para motivar las ventas en el equipo, decidimos incorporar un cambio: categoras senior y junior. Un vendedor senior tendr a cargo a un junior. Un vendedor senior recibe como parte del premio un adicional correspondiente al 3% de las ventas realizadas por la persona que tiene a cargo. Un Junior tiene un porcentaje de descuento en su premio. Por otra parte, si un vendedor junior hace bien las cosas, con el tiempo puede pasar a ser seniorLa codificacin propuesta en el enunciado es:Wollokclass VendedorEspecialista { const ventas = [] method premio(){ return 100 * ventas.length() }}class VendedorSalon { const ventas = [] var premio method premio(){ return premio }}class VendedorSalonSenior inherits VendedorSalon { var junior method premio(){ return super()+self.adicionalJunior() } method adicionalJunior(){ return junior.totalVentas()*0.03 }}class VendedorSalonJunior inherits VendedorSalon { var descuento method totalVentas(){ return ventas.sum({ venta =&gt;venta.monto()}) } method premio(){ return super()*(1 -self.descuento()) }}class VendedorEspecialistaSenior inherits VendedorEspecialista { var junior method premio(){ return super()+self.adicionalJunior() } method adicionalJunior(){ return junior.totalVentas()*0.03 }}class VendedorEspecialistaJunior inherits VendedorEspecialista { var descuento method totalVentas(){ return ventas.sum({ venta =&gt;venta.monto()}) } method premio(){ return super()*(1 -self.descuento()) }}La solucin propuesta tiene problemas que surgen por el mal uso de herencia. Los que podemos destacar son: Repeticin de cdigo: La forma de subclasificar a los vendedores tanto por tipo de vendedor (Saln o Especialista) como por categora (Senior o Junior) hace que tengamos cdigo repetido entre las hojas del rbol de herencia. Esto tiene problemas, sobre todo si el sistema sigue creciendo de esta forma, ya que la repeticin de cdigo es exponencial y realizar un cambio en la lgica del premio de los juniors por ejemplo se propagara para todos los tipos de vendedores habidos y por haber (tiene problemas de extensibilidad). Problemas con la identidad de los objetos: El enunciado indica que un junior puede volverse senior con el tiempo, pero el modelo que tenemos no soporta este tipo de cambio en tiempo de ejecucin. Un objeto de la clase VendedorSalonJunior no puede cambiar de clase a VendedorSalonSenior, su clase es algo que se mantiene durante toda la vida del objeto. Si tratamos de emular el cambio de clase creando un nuevo objeto y copiando los valores de sus atributos segn corresponda lograremos tener el comportamiento de senior pero ya no ser el mismo objeto para el sistema. En OOP una de las caractersticas de un objeto es su identidad, la cual estaramos perdiendo si tomamos esa decisin y el problema asociado a este cambio es que todos los objetos que tengan una referencia a nuestro vendedor promovido debern enterarse de este cambio (y seguramente no lo hagan) para referenciar al nuevo objeto que lo reemplaza. La consecuencia de esto es o bien una complejidad espantosa para mantener las referencias o un sistema inconsistente.Cmo se soluciona este problema? Si cambiamos el modelo para que la categora (Junior o Senior) sea un objeto aparte que el vendedor conozca y delegamos en este objeto todo aquello que corresponda a ser senior o junior solucionamos ambos problemas a la vez, ya que el valor de las referencias s puede ser cambiado en tiempo de ejecucin, es slo settear un atributo. Veamos cmo queda la nueva solucin:Wollokclass Vendedor { const ventas = [] var categoria method premio(){ return categoria.premioPara(self) } method totalVentas(){ return ventas.sum({ venta =&gt;venta.monto()}) }}class VendedorEspecialista inherits Vendedor { method premioBase(){ return 100 * ventas.length() }}class VendedorSalon inherits Vendedor { var premioBase method premioBase(){ return premioBase }}class Senior { var junior method premioPara(unVendedor){ return unVendedor.premioBase()+self.adicionalJuniorPara(unVendedor) } method adicionalJuniorPara(unVendedor){ return junior.totalVentas()*0.03. }}class Junior { var descuento method premioPara(unVendedor){ return unVendedor.premioBase()*(1 -self.descuento()) }}Disclaimer: el mtodo totalVentas se termina definiendo en la clase Vendedor porque tena sentido para todos en este dominio, no slo para los juniors. Para que fuera totalmente anloga podramos tenerlo definido en Junior y delegar en la categora, pero siendo que no es invlido que los vendedores lo definan, era ms sencillo resolverlo de esta forma. En caso de dudas de dominio, siempre vale preguntar.Como se puede ver en el diagrama de clases de la solucin con composicin, para crear un vendedor ya no alcanza slo con elegir la clase del tipo de vendedor que queremos e instanciarla, sino que tenemos que instanciar dos objetos (al vendedor que queramos y su categora) y hacer que el vendedor conozca a su categora, lo cual agrega una complejidad extra para la creacin de nuestros objetos. Si ms adelante quisiramos que un vendedor tambin pueda pasar de ser vendedor de saln a especialista y viceversa, podra plantearse una solucin en la cual el vendedor conozca a su categora y tambin a su modo de venta, complicando ms el armado de un vendedor a cambio una mayor flexibilidad del modelo.A modo de resumen rpido:Herencia Esttica (no puedo cambiar la clase de un objeto en run-time, si creo otro objeto se pierde la identidad lo cual trae problemas) Menos objetos -&gt; Menos complejidad Es una relacin entre clases! Es mucho ms fuerte que la relacin entre instancias planteada en composicin. La herencia implica no slo heredar cdigo sino conceptos.Composicin Dinmico (la implementacin se puede cambiar en run-time, ya que se basa slo en un atributo que se puede settear en cualquier momento con otro objeto que sea polimrfico) Aumenta la cantidad de objetos -&gt; Mayor complejidad (Es ms complicado entender el todo y hay que configurar adecuadamente las relaciones entre los objetos) Se reparten mejor las responsabilidades en objetos ms chicos" + +} , + +{ + +"title" : "Composicion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/composicion.html", +"date" : "", +"content" : "Qu es composicin?Qu queremos decir con Componer?Lo mismo que con composicin de funciones en matemtica.fog(x) es lo mismo que f(g(x))Es decir que lo que devuelve g, hay que aplicrselo a f. A tener en cuenta, tanto f como g tienen que ser funciones, no podemos componer una funcin con un 2, o un 2 con una lista. Slo podemos componer funcionesPara componer dos funciones en Haskell, por ejemplo f y g, se hace asf.geso arma una nueeeva funcin, resultado de componer f con g.Ejemploeven.succEsta formada por la composicin de even que recibe un numero y devuelve un Bool que indica si es par o no, y succ que recibe un numero y devuelve el siguiente. Esa composicin te devuelve una nueva funcin que recibe un nmero y te devuelve el resultado de primero sumarle uno y luego ver si es par:(not.even)2(esperoseentiendanmisflechitasxD)^|^||__||____|Fijate que el 2 se aplica a la funcin de la derecha y el resultado de eso se aplica a la funcin de la izquierda. Y ese sera el resultado final de la funcin.Tanto lo de la izquierda como lo de la derecha del punto, tienen que ser funciones que reciban 1 parmetro (al menos en paradigmas, lo otro es ms complejo). Y a su vez, el tipo que retorna la funcin de la derecha, tiene que ser el mismo que el tipo que espera recibir la funcin de la izquierda. En este caso, even es una funcin que recibe un Integral (ver typeclasses) y retorna un Bool.even::Integrala=&gt;a-&gt;Booly not recibe un Bool y retorna otro.not::Bool-&gt;BoolConviene prestar atencin a lo siguiente: lo que devuelve even, coincide con lo que recibe not. Eso hace posible la composicin!Preguntas FrecuentesEs necesesario que esten los puntos para que sea composicion?Porque para m est implcito que hay composicin, si por ejemplo en lugar de:impar=not.evenpongoimpar=notevenS, es necesario. En el segundo ejemplo estas aplicando even a not, y not espera un Bool, no una funcin y por ende, ni compila por error de tipos.En cambio, cuando hacsnot.evenests armando una nueva funcin que recibe un nmero, ve si es par y despus lo niega. La forma de armar la funcin que quers, segn el segundo ejemplo sera:not(even3)Y en el segundo se aplicara as:(not.even)3Cundo usar composicinCul es la diferencia entre estas dos definiciones?imparn=not(evenn)impar=notevenEn un primer nivel de anlisis, ambas definiciones son equivalentes.Sin embargo, si analizamos solamente las expresiones a la derecha del igual encontramos quenot(evenn)ynot.evenson distintas: la primera denota un valor booleano (True o False) mientras que la segunda denota una funcin.Esta segunda expresin es ms poderosa en cuanto a que nos permite hacer ms cosas que la primera, ya que la construccin de la funcin independiente de su aplicacin sirve, por ejemplo, para trabajar con funciones de orden superior.En cuanto a la definicin de funcin, no tiene grandes ventajas sobre salvo que nos ayuda a entrenarnos en el uso de la composicin, que despus podemos utilizar para otras cosas. Sin embargo, una de las virtudes asociadas si se reemplazan muchas aplicaciones anidadas por composicin de funciones podra implicar un cdigo ms limpio, porque la sintaxis de Haskell est diseada de modo que eso suceda.Errores comunesEjemploSupongamos una lista de alumnos de los cuales se sabe su nombre y su nota. Queremos obtener los nombres de los alumnos aprobados.Podemos suponer adems la existencia de las funciones:nombres:: [Alumno] -&gt; [String]aprobados:: [Alumno] -&gt; [Alumno]Un error que veo con frecuencia es hacer:nombreDeAprobadosalumnos=nombres.aprobadosalumnosLa composicin es una operacin entre funciones esto quiere decir que a ambos lados del . debe haber una funcin. Qu hay a cada lado del . en este caso: nombres , no hay problema: es una funcin (de listas de alumnos/tuplas en listas de nombres); aprobados alumnos s hay problema! No es una funcin, es una lista de alumnos. Dicindolo en fcil: debo componer funciones, no vale componer valores. Si yo a una funcin le aplico todos los parmetros deja de ser una funcin y pasa a ser un valor simple. En este caso, aprobados es una funcin, mientras que aprobados alumnos es un valor, y como tal no se puede componer. Tal vez sea interesante ver el efecto de la currificacin en Haskell.Correcciones posiblesSin composicinaprobadosalumnos=nombres(aprobadosalumnos)Es decir uso aplicacin en lugar de composicin (ojo, esto funciona pero si en estamos en un parcial y se desea evaluar que el alumno sepa composicin ah no estn usando composicin entonces puede no ser suficiente como solucin al ejercicio).Con composicinnombreDeAprobados=nombres.aprobadosClaramente son funciones las dos expresiones a ambos lados del .. (Notese que a la derecha del = tambin hay un parmetro menos.)Pueden encontrar otro ejemplo sobre esta clase de errores en Errores con composicin y aplicacin parcialComposicin vs. AplicacinPara terminar de entenderlo recuerden la matemtica, es lo mismo que ? Claramente si g es una funcin yo no puedo hacer . Por otro lado, si en lugar de una funcin g tuviera un valor real x, entonces puedo hacer pero no .Algunos detalles tcnicosSi bien en general intentamos concentrarnos en los conceptos y no prestar tanta atencin al conocimiento en s del lenguaje; para poder expresar correctamente una composicin en Haskell es necesario comprender correctamente algunos detalles de la sintaxis del Haskell: Si pongo un . es composicin, sino es aplicacin. Los dos conceptos son bien distintos y es muy importante comprender la diferencia; por lo tanto es necesario ser bien explcito sobre cundo se esta queriendo utilizar uno u otro. En criollo, se tiene que notar dnde hay un punto y dnde no. El operador de composicin tiene poca precedencia. (Ver Aplicacin Parcial) Por lo tanto la expresin not . even 3 debe leerse como not . (even 3) (y por lo tanto es incorrecta). Una alternativa posible es alterar la precedencia explcitamente usando parntesis, por ejemplo (not.even) 3; donde primero se componen las funciones, eso produce una nueva funcin, y a esa nueva funcin le aplico el 3 como parmetro. Para ms informacin puede leer: Precedencia de los operadores ms comunes en Haskell y Cundo usar parntesis" + +} , + +{ + +"title" : "Comunicacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/comunicacion.html", +"date" : "", +"content" : "Cuando construimos modelos mentales sobre los problema que queremos resolver, ya sea como parte del proceso de anlisis, diseo, etc, normalmente queremos luego transmitirlos Esto ocurre porque: Queremos compartirlo con otros: para explicar nuestro modelo construido e intercambiar opiniones sobre el mismo Queremos construir documentacin: una referencia persistente sobre lo que hemos pensado, la cual ser una fuente de consulta para otros o nosotros mismos en un futuro mas o menos lejano, cuando ya hayamos olvidado la informacin que recopilamos y las decisiones que tomamos.Formas de comunicacinTenemos varias formas de comunicar estas ideas, por ejemplo un texto en prosa una especificacin de CU en la etapa de anlisis una porcin de cdigo o pseudocdigo en la etapa de diseo un caso de pruebason formas validas de comunicarlas. Otra forma til son los diagramas, que normalmente son menos detallados pero transmiten las ideas principales de nuestra realidad modelada ms rpidamente.Los diagramas empleados para comunicar varan en funcin de su objetivo; probablemente necesite diagramas diferentes para comunicar ideas diferentes. No es lo mismo mostrar la disposicin de los servidores en un sistema distribuido que la disposicin de los componentes visuales en una interfaz grfica.Por otro lado, el tipo de diagrama que construyamos depende del paradigma en el que estoy modelando: la naturaleza de los componentes y su responsabilidades es diferente, por ejemplo, en el paradigma procedural y en el orientado a objetos.Finalmente, muchas veces emplearemos distintos diagramas que modelan de forma complementaria aspectos diferentes de la misma cosa.UMLUML significa Unified Modeling Language (Lenguaje Unificado de Modelado) y basicamente son un conjunto de especificaciones para hacer muchos (realmente muchos) diagramas de distintos tipos. Es un lenguaje que nos permite comunicar ideas de diseo desde diferentes puntos de vista, y con distinto enfoques. UML se compone de una serie de diagramas, donde cada uno tiene un objetivo en cuanto a lo que quiere comunicar.Ac hay alguno de los diagramas de UMLUna ventaja no menor de UML frente a otros como por ejemplo LePUS es su amplia difusin, lo que significa que son conocidos por una gran parte de los perfiles, y que adems, existen muchos aplicativos para su construccin." + +} , + +{ + +"title" : "Concepto de funcion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/concepto-de-funcion.html", +"date" : "", +"content" : "Como su nombre lo indica, la funcin es el concepto fundamental del paradigma funcional: mientras que, por ejemplo, en el paradigma de objetos, los problemas se resuelven en trminos de envo de mensajes entre objetos, en funcional los programas se estructurarn en torno a aplicacin de funciones sobre valores. La funcin, es as, pues, la computacin caracterstica del paradigma.EnfoquesFuncin como caja negraUna forma simple de pensar una funcin es como una mquina con una salida y al menos una entrada, capaz de producir un resultado. Decimos que se trata de una caja negra, porque para aquel que la use no tiene acceso al interior de la misma, sino tan solo a sus entradas y salida. Esto nos lleva a que las funciones pueden ser combinadas fcilmente, de diversas formas, tan solo conociendo el tipo de entradas y salidas que posee.Funcin como transformacin matemticaLas funciones, sin embargo, no son simples cajas negras, que podran, por ejemplo, tener memoria de sus entradas anteriores, sino que son transformaciones matemticas que presentan transparencia referencial.En particular, las funciones son relaciones que presentan las siguientes caractersticas: para toda entrada aceptable (su dominio), existe un nico resultado (imagen), lo cual se conoce como unicidad. para toda entrada del dominio, existe un resultado, lo que se conoce como existencia.Funcin desde un punto de vista proceduralAl llevar los conceptos de funcin matemtica al mundo computacional, la transparencia referencial implica que las funciones, comparadas contra los procedimientos imperativos, no tienen efecto, su aplicacin no afecta al contexto, o, cuando menos, no es visible para el observador que evalua la expresin.Si bien no tiene sentido hablar de mutabilidad en el contexto matemtico, dado que solo se manejan valores y no referencias (al menos, en un enfoque simplista), la transparencia referencial en los programas construidos en el paradigma funcional tiene dos consecuencias mas o menos evidentes: Las funciones no pueden mutar sus argumentos ni otras variables, locales o globales, ni directa ni indirectamente. Esto se garantiza al eliminar la asignacin destructiva del lenguaje. (podemos decir que las variables no varan) Las funciones no pueden realizar de forma directa operaciones de entrada/salida (aunque existen estrategias para realizarlas indirectamente preservando a la funcin pura)Funcin como un TADLas funciones currificadas, en tanto valores, pueden ser tambin pensandas como un TAD, para el cual: su nica operacin primitiva es la aplicacin, definida entre una funcin y otro valor. Esta operacin, a su vez tambin es una funcin, llamada apply, (funcin ($) en el Prelude de Haskell). Las dems operaciones complementarias, como la composicin, se construyen a partir de la aplicacin. sus valores son cada una de las funciones posibles. As, por ejemplo, even, odd, (+) son todos valores del tipo funcinFuncin desde el clculo lambdaDesde el punto de vista del clculo lambda, la funcin es LA primitiva del lenguaje, y todas las funciones son annimas, es decir, son expresiones lambda. Todo, hasta los nmeros, pueden ser expresados con una funcin con suficiente imaginacin.Funciones en HaskellLas funciones en Haskell presentan todas las carectersticas mencionadas anteriormente. A modo de resumen, decimos que: Las funciones son transformaciones matemticas, que presentan transparencia referencial, y por tanto libres de efecto Las funciones son valores Las funciones tienen tipo funcin ((-&gt;) a b), que est determinado por su dominio e imagen. Una funcin de enteros en booleanos tiene tipo Int -&gt; Bool Las funciones son un caso particular de las relaciones, que presentan unicidad y existencia para todo su dominio. Las funciones estn currificadas, por lo que no existen funciones de ms de un argumento realmente, sino que se emulan a partir de funciones de un argumento que devuelven otra funcin que toma los parmetros restantes. La operacin primitiva de la funcin es la aplicacin, por la cual se evala una funcin pasandole sus argumentos y obteniendo un resultado El mecanismo de la evaluacin de las funciones es la reduccin (reduccin ) Dado que la nica operacin primitiva del tipo funcin es la aplicacin, slo es funcin aquello todo y slo lo que pueda ser aplicado. Moraleja: no tiene sentido hablar de funciones de cero argumentos, ya que no pueden ser aplicadas" + +} , + +{ + +"title" : "Conceptos basicos del diseno", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/conceptos-basicos-del-diseno.html", +"date" : "", +"content" : "ModeloUn modelo es una simplificacin. Es una interpretacin de la realidad que abstrae los aspectos relevantes para la solucin de un problema. (Definicin extrada de Domain Driven Design de Eric Evans.DominioTodo programa de software que se va a construir, surge como una idea, o una necesidad, que est relacionada con alguna actividad o inters. Estas actividades o intereses y el conjunto de reglas y caractersticas que lo componen, son el dominio de un problema. Cuando vayamos a construir un programa, debemos conocer y entender el dominio para poder encarar una solucin al problema que tenemos. Por supuesto que la informacin puede ser mucha, y en algunos casos difcil de entender, por lo que debemos crear modelos que simplifiquen, seleccionen y estructuren el conocimiento de manera de enfocarlo en lo que necesitamos para solucionar el problema.HeursticaLa heurstica es una medida. No es una medida cuantitativa como una longitud o un peso, sino una medida que me permite establecer un valor de referencia de una caracterstica cualitativa.Podemos hablar de que una heurstica es una buena prctica, que permite comparar dos objetos de estudio en base a una determinada caracterstica. No vamos a poder establecer un valor numrico para compararlos pero igualmente nos va a poder permitir saber si un objeto es ms o menos que el otro en ese aspecto.Por ejemplo, si hablamos de la simplicidad de un diseo, no podemos decir que un sistema tenga complejidad 3.5 complejidoios; pero s podemos decir que un diseo es ms o menos simple que otro.Las heursticas son tiles cuando no disponemos de los medios cientificos para usar otras medidas.Es equivocado buscar que una heurstica se convierta en un nmero medible, eso resulta contradictorio por su propia definicin. Por lo tanto, en elementos cualitativos, es imposible establecer medidas cuantitativas. Aunque resulte tentador convertir una heurstica en una medicin debemos evitar esa tentacin a todo costo.Por ejemplo un error comn es hablar de complejidad en nmero de clases o nmero de mtodos, de la misma manera que no podemos medir la complejidad de una solucin por la cantidad de lneas de cdigo involucradas. Estas medidas son apenas indicios pero es necesario analizar las clases, los mtodos, el cdigo para poder determinar si efectivamente esa solucin resulta ms compleja que otra.Cohesin Una clase es cohesiva si podemos definirle un objetivo claro y puntual. Un mtodo es cohesivo si tiene un nico objetivo.Emitir una factura y calcular el total de facturacin est bueno que estn en diferentes mtodos. En general, tener mtodos con efecto colateral (emitir factura, realizar un descuento, firmar una libreta de un alumno, cambiar el sueldo bsico a un empleado) y mtodos que no tengan efecto (conocer el sueldo de un empleado, saber el promedio de notas de un alumno en finales, conocer el total de facturacin de un mes para un cliente, etc.) es una buena prctica, tambin es bueno abstraer ideas que se repiten en la misma clase dndole un nombre y dejndolo en un mtodo aparte. As por un lado evitamos duplicar cdigo y por otro aumenta la cohesin de un mtodo: se concentra en hacer slo una cosa por vez.Por eso mismo un Cliente representa todo lo que un cliente puede abstraer. Si hay una clase Empresa es porque representa para nosotros una abstraccin importante en el sistema, no para que la Empresa tome decisiones que son del cliente. El cliente tiene atributos + comportamiento. As aumentamos la cohesin de nuestro sistema. De lo contrario, la Empresa toma responsabilidades de un Cliente, de un Empleado, etc. y como hace muchas cosas a la vez, el objetivo que cumple es difuso y la consecuencia de esta menor cohesin es el impacto que tiene cualquier modificacin de la estructura interna de un cliente, un empleado o una factura.AcoplamientoEs el grado en que los componentes de un sistema se conocen.Un cliente conoce sus facturas para calcular el total, y est bien que las conozca. Lo que es nocivo para el cliente es conocer de ms o de menos. De ms porque si el cliente le pide las lneas (los renglones) a cada factura y luego a cada lnea le pide el precio unitario de cada producto, cualquier modificacin en el clculo del precio de un producto (por ejemplo, descuento por cantidad dependiente del producto), el que se ve directamente afectado es el cliente.Ejemplo de cdigo con alto nivel de acoplamientopublicBigDecimalgetMontoTotal(){BigDecimaltotal=newBigDecimal(0);for(Facturafactura:this.facturas){for(Renglonrenglon:factura.renglones){total=total.add(renglon.getProducto().getPrecioUnitario()*renglon.getCantidad());}}returntotal;}Aqu vemos que un cliente conoce a objetos factura, pero tambin a renglones de factura y a productos.Si el cliente conoce de menos no tiene forma de saber el total de facturacin si no sabe que cada factura tiene como interfaz un mtodo que me permite saber el totalpublic BigDecimal getTotal()El mismo ejemplo con nivel adecuado de acoplamiento entre cliente y facturapublicBigDecimalgetMontoTotal(){BigDecimaltotal=newBigDecimal(0);for(Facturafactura:this.facturas){total=total.add(factura.getTotal());}returntotal;}Acoplamiento explcito e implcitoEn algunos casos, el acoplamiento entre dos entidades de software no es fcilmente detectable, por lo que se llaman acoplamientos implcitos. Esto se produce cuando una entidad de software para su funcionamiento depende de una caracterstica de otra que no est visible en su interfaz pblica y en cambio forma parte de su implementacin interna. En algunos libros este concepto puede encontrarse mencionado como Program to an interface, not to an implementation.El acoplamiento entre dos entidades de software produce una dependencia: un cambio en una de ellas posiblemente produzca un cambio en la otra. Al modificar una entidad de software es importante poder conocer cules son todas las otras entidades que pudieran ser afectadas por este cambio. Por eso, en el caso en que tengamos un acoplamiento, siempre es preferible que lo explicitemos, ya que facilitar la mantenibilidad del sistema y nos dar una herramienta para asegurar la consistencia ante las modificaciones.Requerimientos y casos de usoUn caso de uso es una secuencia de interacciones que se desarrollarn entre un sistema y sus actores en respuesta a un evento que inicia un actor principal sobre el propio sistema. Cuando hacemos especificaciones de los casos de uso definimos la interaccin entre usuario y sistema, dejando claro el lmite entre lo que debe proporcionar el usuario y lo que el sistema debe responder.Los casos de uso pueden ser tiles para establecer requisitos de comportamiento, pero no establecen completamente los requisitos funcionales ni permiten determinar los requisitos no funcionales. Los casos de uso deben complementarse con informacin adicional como reglas de negocio, requisitos no funcionales, diccionario de datos que complementen los requerimientos del sistema.Un requerimiento es algo que el sistema debe hacer para lograr el objetivo de un usuario.Ms sobre requerimientosLinks relacionados Volver a Diseo de Sistemas" + +} , + +{ + +"title" : "Conceptos de ingenieria de software y de sistemas", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/conceptos-de-ingenieria-de-software-y-de-sistemas.html", +"date" : "", +"content" : "Ingeniera de software e ingeniera de sistemasQu es un sistema?Sistemas legacy, desarrollos a medida y enlatadosProceso de softwareRequerimientosRequerimientos funcionalesLos requerimientos funcionales son las capacidades o funcionalidades de un sistema de software. Detallan el comportamiento del sistema. En otras palabras, lo que el sistema debe proveer. Hay distintos tipos de requerimientos no funcionales:Procesos de NegocioLos procesos de negocios permiten especificar como un proceso se lleva a cabo a travs de la organizacin, ya que requiere intervencin de diferentes actores y reas, en diferentes lugares y tiempos.Casos de UsoLos caso de uso definen una interaccin entre un actor y el sistema, para lograr un objetivo de negocio especifico en un lugar y momento especifico.Requerimientos no funcionalesLos requerimientos no funcionales son aspectos que debe tener el sistema, estos pueden o no ser especficos de una funcionalidad (el tiempo de respuesta para procesar el alta de una tarjeta SUBE va web no debe exceder los 3 segundos o el sistema debe funcionar 7 x 24), definen la calidad y las caractersticas que el sistema debe soportar. Tambin conocidos como atributos de calidad, o cualidades del software algunos de estos son: Performance Availability (Disponibilidad) Security (Seguridad) Testability (Testeabilidad) Modifiability (Modificabilidad) Usability (Usabilidad)Ejemplos de restricciones posibles: tecnolgicas: el sistema debe funcionar en un browser Internet Explorer 8 superior, Mozilla Firefox 5.0.3 y Safari en cualquier versin, tiene que construirse en una tecnologa Open Source, tiene que ser Web based normativas o legales: el sistema debe estar construido segn estndares de ley Sarbanes-Oxley, el software debe contemplar que el proceso de fabricacin de los productos se adapte a las normas ISO 9000, el sistema debe cumplir con el anlisis de vulnerabilidad dispuesto por la gerencia de Seguridad Informtica de calidad: disponibilidad: el sistema debe estar disponible 6 x 20 / 7 x 24, performance: las consultas de cliente por nombre no pueden tardar ms de 3 segundos, escalabilidad: se debe pemitir agregar nuevos tipos de cliente en el futuro, usabilidad: el sistema debe permitir a un usuario nuevo capacitarse en menos de una semana.Ms sobre cualidades del softwareLinks relacionados Volver a Diseo de Sistemas" + +} , + +{ + +"title" : "Configuracion de maven para poder utilizar las herramientas de uqbar", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/configuracion-de-maven-para-poder-utilizar-las-herramientas-de-uqbar.html", +"date" : "", +"content" : "Para poder utilizar los artefactos Maven desarrollados por Uqbar debemos agregar los repositorios de donde bajar los artefactos de Uqbar a la configuracin de Maven. Esta configuracin se debe indicar en el archivo settings.xml, que se ubica en: Windows: tu directorio de usuario + .m2&#92;settings.xml. Por ejemplo, si tu usuario es Juana, e instalaste Windows en el disco C:, debera estar en C:&#92;Users&#92;Juana.m2&#92;settings.xml Linux: tu directorio de usuario (~) + .m2/settings.xml. Por ejemplo, si tu usuario es juana, debera estar en ~/.m2/settings.xml o /home/juana/.m2/settings.xmlDado que .m2 es un directorio oculto, debs activar la configuracin para verlos. Te dejamos las instrucciones para Windows y LinuxEl contenido de tu archivo settings.xml debera quedar as:&lt;settings xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"&gt; &lt;profiles&gt; &lt;profile&gt; &lt;id&gt;uqbar-wiki&lt;/id&gt; &lt;repositories&gt; &lt;repository&gt; &lt;id&gt;uqbar-wiki.org-releases&lt;/id&gt; &lt;name&gt;uqbar-wiki.org-releases&lt;/name&gt; &lt;url&gt;http://maven.uqbar.org/releases&lt;/url&gt; &lt;/repository&gt; &lt;repository&gt; &lt;snapshots/&gt; &lt;id&gt;uqbar-wiki.org-snapshots&lt;/id&gt; &lt;name&gt;uqbar-wiki.org-snapshots&lt;/name&gt; &lt;url&gt;http://maven.uqbar.org/snapshots&lt;/url&gt; &lt;/repository&gt; &lt;/repositories&gt; &lt;/profile&gt; &lt;/profiles&gt; &lt;activeProfiles&gt; &lt;activeProfile&gt;uqbar-wiki&lt;/activeProfile&gt; &lt;/activeProfiles&gt; &lt;/settings&gt;" + +} , + +{ + +"title" : "Configuraciones generales para cualquier eclipse", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/configuraciones-generales-para-cualquier-eclipse.html", +"date" : "", +"content" : "Hay varias cosas que es til configurar en Eclipse, independientemente del lenguaje que elijan.Configuraciones adicionales de EclipseInstalled JREUna de las configuraciones ms importantes, es el compilador que estar usando Eclipse para nuestro cdigo Xtend. En el ejemplo de arriba, hemos configurado un compilador de Java 1.11 (consult con tus docentes qu versin de JDK hay que usar). Es preciso recalcar que deben apuntar a una JDK (con el compilador) y no a una JRE o no podrn ejecutar ningn programa Xtend, ni Java.A continuacin te dejamos una animacin que muestra cmo configurar otra JDK, para lo cual hay que pasar el directorio raz (no el bin donde residen el compilador y los dems programas de Java).New &gt; Artefactos de XtendPara que cuando hagas New &gt; File te aparezcan las clases y las interfaces Xtend, Window &gt; Customize Perspective &gt; solapa Menu Visibility &gt; expands File &gt; New &gt; y seleccions las de Xtend (Xtend class, inteface, annotation y enum).CompilerAlgunas versiones de Eclipse utilizan por defecto compatibilidad con el compilador Java 1.4, algo que no es conveniente si vamos a trabajar con herramientas como Generics o Annotations que vienen a partir del JDK 1.5.Para esto deben ir a Window Preferences &gt; Java &gt; Compiler &gt; y donde dice JDK Compliance subir la propiedad Compiler compliance level de 1.4 a una superior.En caso contrario al bajar proyectos compilados en JDKs superiores aparecern mensajes de error como estos:Syntaxerror,annotationsareonlyavailableifsourcelevelis1.5orgreaterSyntaxerror,parameterizedtypesareonlyavailableifsourcelevelis1.5orgreaterEncoding (slo Windows)Para no tener problemas con los tildes y dems caracteres especiales al bajarse los ejemplos conviene tener sincronizado el mismo encoding. Para eso, desde la barra de men: Window &gt; Preferences, filtrar por encoding y cambiar todos a UTF-8 o ISO 10646/Unicode(UTF-8). Por ejemplo: En General &gt; Workspace &gt; Text file encoding, seleccionar Other &gt; UTF-8. Aplicar cambios.SpellSi van a programar en espaol, es recomendable desactivar el diccionario (viene por defecto en ingls). Para ello filtrar en el men por la palabra spell y desactivar la correccin ortogrfica (Spelling &gt; desactivar el check Enable spell checking). Aplicar cambios.Otra opcin es que se bajen un diccionario espaol de internet y lo configuren.WarningsEn varios lenguajes de la JVM nos aparecer una molesta advertencia sobre la serializacin de clases, algo que por el momento no necesitamos. Conviene desactivar el warning default de clases serializables que no definan un identificador de versin: Window &gt; Preferences, filtrar por Serializable, solapa Java / Compiler / Errors/Warnings, Potential programming problems, y se setea el valor de Serializable class without serialVersionUID a Ignore. Aplicar cambios.Opcionalmente, nosotros recomendamos subir a Warning estas dos configuraciones Potential null pointer access Redundant null checkShortcutsEn algunas distribuciones de Linux existe un shortcut por defecto que es Ctrl + Space, que colisiona con el shortcut del content assist de Eclipse . Para solucionar el problema, hay que deshabilitar el binding: en Ubuntu: System Settings -&gt; Keyboard-&gt; Shortcuts en Lubuntu: click en el logo que esta abajo a la izquierda -&gt; Preferencias -&gt; Metodos de entrada por Teclado y se cambia a DisabledConfiguracin de MavenWindow &gt; Preferences &gt; Maven, debe tener esta configuracin: Download repository index on startup, al igual que Update Maven projects on startup deben estar destildados para evitar demoras al iniciar tu Eclipse Por el contrario, Download Artifact Sources y Download Artifact JavaDoc deben estar tildados, porque eso descargar documentacin y fuentes de los componentes que uses, algo bastante til cuando necesitamos solucionar un error o entender de qu manera comunicarnos con l. la marca Offline debe estar destildada, o no intentar conectarse a Internet para bajar componentes.Filtros de paquetesEn un JDK estndar hay muchos paquetes, y slo usaremos unos pocos. Es recomendable indicarle a Eclipse que no nos sugiera paquetes que casi con seguridad no usaremos.Para eso, en Java &gt; Appearance &gt; Type Filters, agregar las siguientes expresiones:bashsun.**.internal.*edu.emory.mathcs.backport.*java.awt.*java.swing.*org.omg.*" + +} , + +{ + +"title" : "Conocimiento de dominio y refactoring", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/conocimiento-de-dominio-y-refactoring.html", +"date" : "", +"content" : "Se puede iniciar un refactoring sin conocimiento del dominio?Se puede refa La respuesta corta es: no, no se puede (*) realizar un refactor sin conocimiento del dominio.Ahora s, la respuesta larga.Primero, aclaremos algunas ideas:dicen que no necesitan conocerlo para hacer un refactoringOjo, lo que comentamos en clase fue que no necesito conocer el dominio para identificar potenciales fallas en el diseo, que se manifiestan a travs del cdigo. Es decir, sin conocimiento de dominio podemos slo identificar code smells, que tienen asociados posibles refactors.S, remarco el posible/potencial porque es importante que entendamos que se trata slo de una heurstica. Quizs el diseo s es correcto, o quizs el refactor que deberamos encarar no tiene nada que ver con lo que propone el code smell. Por eso, tambin ojo con esto:pero no hace falta saber nada acerca del dominio para darte cuenta que tenes q delegar en subclases en ves de preguntar por el tipoEsto tampoco es correcto, si bien es muy probable que haya que emplear polimorfismo (y no necesariamente utilizar herencia), necesitaremos conocer al dominio y a la tecnologa como para poder justificar ese cambio (**) . De lo contrario, si pensaramos que para toda estructura de cdigo que se corresponde con un code smell hay un cambio que tenemos que realizar, estariamos (casi) insinuando que hay aspectos del diseo automatizables. Yo prefiero descreer de esto.En resumen hasta ac, parafrasendote, no necesito conocer al dominio para encontrar code smells, pero s lo necesito para saber si efectivamente hay una falla de diseo, y en tal caso, determinar el refactor ms apropiado que los subsane.Pero este otro comentario:si el sistema tiene un elevado nivel de acoplamiento, hacer un refactoring de algo te lleva a cambiar 90 cosas msque a menos que sepas como viene el sistema y cul es la funcionalidad de cada parte y su dependencia, no lo vas a poder hacerme lleva a otra pregunta: supongamos que tenemos conocimiento del dominio; podemos realizar un refactor sin conocimiento del diseo actual? Se los dejo para pensar, sera interesante si alguien se anima proponer una solucin al dilema (sic).Y finalmente, buena observacin:despus de cada modificacin en el diseo hay q actualizar la documentacins, si modificamos el diseo de un sistema, deberamos impactarlo en la documentacin que llevemos de este. Como eso puedo ser tedioso, y en los momentos iniciales del desarrollo de un sistema los cambios de diseo son constantes, es frecuente postergar la realizacin de una documentacin exhaustiva hasta que el diseo a ms alto nivel (llammoslo arquitectura) quede estabilizado.Saludos!(*) no se puede en sentido informal: es ciertamente posible hacerlo, pero no es una gran idea, por lo expuesto precisamente por vos, al menos para bases de cdigo (proyectos) no triviales.Por ejemplo, en nuestro ejercicio de monedero, el dominio era muy simple: poner y sacar dinero en una cuenta, llevando un historial del mismo, y validando algunas reglas de negocio, por eso con apenas algunos minutos de anlisis podamos saber qu refactorizar. Pero en sistemas con dominios ms complejos y muchas ms tecnologas involucradas, hubiramos necesitado mucho ms tiempo para determinar exactamente qu hacer." + +} , + +{ + +"title" : "Creacion de objetos con parametros", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/creacion-de-objetos--con-parametros.html", +"date" : "", +"content" : "Eso, lo que dijo Leo. Pero algunas cositas ms En Smalltalk no hay constructores, hay mensajes y ya.Todos los mensajes devuelven un objeto (p.ej. cuando le pons el ^ sombrerito). Los mtodos que no tienen el sombrerito, es como si abajo de todo dijeran ^self.p.ej. Golondrina &gt;&gt; energia: unaEnergia"Setterdelavariableenergia"energia:=unaEnergia.^selfEntonces no hay constructores, pero podemos hablar de mensajes que le mandamos a la clase (mensajes de clase) y que devuelven una instancia de esa clase. Lo que pods hacer es implementar tus propios mtodos de clase.El mensaje new no recibe parmetros, as que con new no vas a poder hacer eso que decsp.ej. pepita := Golondrina nuevaEnergiaInicial: 100 ubicacionActual: buenosAires. &lt;&#92;&#92;En un workspace&gt;El objeto que recibe el mensaje es la clase Golondrina, entonces self dentro del mtodo &#92;#nuevaEnergiaInicial:ubicacionActual: apunta a la clase Golondrina------------------------------------------------------------------------(Mtodo de clase de Golondrina) nuevaEnergiaInicial: unaEnergia ubicacionActual: unLugar`|nuevaGolondrina|``"InstanciamosunanuevaGolondrina,acordatequeselfapuntaalaclaseGolondrinaenesteejemplo"``nuevaGolondrina:=selfnew.``"Lemandamoselmensajeenergia:alanuevainstancia"``nuevaGolondrinaenergia:unaEnergia.``"Lemandamoselmensajeubicacion:alanuevainstancia"``nuevaGolondrinaubicacion:unLugar.``"Sinoescribimosnadamsdevolveraself,enestecasolaclaseGolondrina,yseromperatodoenelworkspacecuandoleempecemosahablarapepita(queapuntaraalaclaseGolondrinaenvezdeaunanuevainstancia"``"Portodoesoagregamos"``^nuevaGolondrina`------------------------------------------------------------------------De todas formas en el propio workspace se puede instanciar en menos lneas sabiendo que los mensajes que son setters devuelven el objeto receptor de ese mensaje"Puse los parntesis en rojo para que se entienda ms, pero no son necesarios"pepita := ((Golondrina new) energia: 100) ubicacion: buenosAires.Como es peligroso asumir eso y no ayuda a la expresividad, se puede usar un operador punto y coma &lt;;&gt; (que es un chiche sintctico de Smalltalk) para mandar mensajes en cascada.Object &gt;&gt; yourself`"Elmensajeyourselfdevuelveself,cuac!"``^self`Escribir pepita := Golondrina new.Es igual a escribir pepita := (Golodrina new) yourself.Escribir "Evaluar todo esto nos devuelve una instancia de la clase Golondrina, con 100 de energia y con buenosAires como ubicacin" pepita := Golondrina new. pepita energia: 100. pepita ubicacion: buenosAires. pepita.Es lo mismo que pepita :=`Golondrinanew``energia:100;``ubicacion:buenosAires;``yourself`Bue, me pareci copado contar todo esto :$Si no se entendi algo prubenlo, usen el inspect y tiene que salir. O de ltima, vuelvan a preguntar =PSaludos,El 9 de mayo de 2009 14:16, Leonardo "Pelado" Cesario &lt;peladosnow@gmail.com&gt; escribi:`Hernan:``Primerotepreguntariasiyavistemetodosdeclase.``Encasoafirmativovospodeshacertumetododecreacion,porejemplonew:``Noesverdadqueelnewenviaelmensajeinitialize(porlomenosnopasaentodaslasversionesdeST)``Sipodesredefinirelnewparaquellamealinitialize.Detodasformaslaideadelinitializeesinicializar(cuak!)elestadointerno,nodepasarleparametros.``Eltemadesilocreoconparametrosoluegoselosmandopormediodeotromensaje,esuntemadediseo.``Esperoseaclareladudayteayudeadecidir.``Saludos!``LeoC`" + +} , + +{ + +"title" : "Creacion de un proyecto maven basico", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/creacion-de-un-proyecto-maven-basico.html", +"date" : "", +"content" : "El objetivo de este tutorial es crear una aplicacin base utilizando las siguientes tecnologas: Java Eclipse Git MavenSe asume la presencia de un entorno con todas esas herramientas configuradas adecuadamente. En caso de duda recomendamos ir al siguiente link.Creacin del proyectoPaso 1: Creacin del proyecto MavenDesde el men principal del Eclipse seleccionamos File &gt; New Project Maven Project. En la primera pantalla del asistente podemos elegir un archetype, o bien chequear la opcin Create a simple project (skip archetype selection) que es la opcin por defecto que vamos a elegir.Al presionar Next, nos aparece el siguiente paso, donde debemos elegir el Group Id refleja la organizacin para la que vamos a construir el proyecto (por lo general depende de la materia que ests cursando) el Artifact Id que se asocia al nombre del proyecto la versin, donde dejamos el valor por defecto Paso 2: Agregar bibliotecas necesarias al pomEn el archivo pom.xml del raz del proyecto podemos agregar bibliotecas a nuestro proyecto en el nodo dependencies&lt;dependencies&gt; &lt;dependency&gt; &lt;groupId&gt;log4j&lt;/groupId&gt; &lt;artifactId&gt;log4j&lt;/artifactId&gt; &lt;version&gt;1.2.13&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;commons-collections&lt;/groupId&gt; &lt;artifactId&gt;commons-collections&lt;/artifactId&gt; &lt;version&gt;3.1&lt;/version&gt; &lt;/dependency&gt;&lt;/dependencies&gt;Tambin podemos cambiar el groupId, artifactId, la versin o bien apuntar a un parent project (para mayor informacin consulte con el docente de su materia)Paso 3: Importacin de la informacin al entornoCada vez que se modifique el archivo pom.xml, debemos actualizar nuestro entorno (Eclipse, IntelliJ o el que fuera) mediante un botn derecho sobre el proyecto Maven &gt; Update project, o bien por lnea de comando hacer:mvneclipse:eclipse-DdownloadSources=true-DdownloadJavadocs=trueCmo encontrar bibliotecasSi no estamos seguros del nombre o la ltima versin de un componente, podemos hacer la correspondiente bsqueda en http://search.maven.orgDefinir repositorios adicionalesSi tenemos bibliotecas que no podamos encontrar en el repositorio default de maven (repo1.maven.com), debemos agregar un repositorio adicional. Hay muchas formas de hacer esto, una sencilla es agregarlo en el pom, antes de las dependencias. Un repositorio posible para esta tarea es el de JBoss, para agregarlo pueden hacer:&lt;repositories&gt; &lt;repository&gt;&lt;id&gt;jboss&lt;/id&gt;&lt;url&gt;http://repository.jboss.org/maven2&lt;/url&gt;&lt;/repository&gt;&lt;/repositories&gt;Links relacionados Una vez creado el proyecto, para que otras personas quieran tenerlo en su propio entorno de trabajo, conviene mirar las instrucciones para descargar un repositorio git. Temario Algoritmos III " + +} , + +{ + +"title" : "Crear un proyecto en xp dev", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/crear-un-proyecto-en-xp-dev.html", +"date" : "", +"content" : "Crear una cuenta de usuario en xp-dev pendienteCrear un proyecto en xp-devCreacin del proyectoUna vez logueados en el sitio de xp-dev, en la solapa de My Projects, abajo de todo se puede ver el formulario Create a New Project.Al completar el formulario se recomienda elegir la opcin Trak como source control. Luego clickear en Create Project.Creacin del repositorio svnEn la pgina siguiente elegir la solapa Source Control y ah seguir el link: Enable Source Control. En el formulario seleccionar la opcin Create Initial Directories y clickear sobre Save.En la pgina resultante se mostrar la URL del repositorio que se acaba de crear, por ejemplo:http://svn2.xp-dev.com/svn/proyecto-de-pruebaEs importante registrar esa URL para poder publicar sus proyectos ah.Configuraciones AdicionalesEligiendo la solapa Settings y desde esa pgina la opcin Permissions se pueden realizar invitaciones a otros usuarios, clickeando sobre Assign Permission To New User." + +} , + +{ + +"title" : "Css", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/css.html", +"date" : "", +"content" : "Es la forma ms recomendada de especificar y modificar las cuestiones estticas de una pgina HTML. La caracterstica principal es que separa estas declaraciones del propio html. As evita ensuciar la informacin (html) con cuestiones estticas (el archivo .css). Adems permite reutilizar estilos entre las diferentes pginas html, manteniendo consistencia entre el estilo de todo el sitio/aplicacin.SintaxisCSS tiene su propio lenguaje declarativo en el cual especificamos reglas. Una regla tiene la siguiente sintaxis:El selector nos permite aplicar el estilo a aquellos elementos que coincidan con dicha expresin. Luego el cuerpo de la regla contiene un conjunto de propiedades y valores para stos.Algunas propiedades aplican solo a algunos tipos de tags. Sin embargo, no es un lenguaje que compile o que tire errores. Simplemente si una propiedad no aplica a un tag, el browser no le va a dar bola.Un primer ejemplo para entender la sintaxisspan{text-align:center;}Aplica el valor center a la propiedad text-align de todos los tags de la pgina que sean de tipo &lt;span&gt; (en otras palabras, alinea un texto en el centro de donde est contenido).Selectores PrincipalesBsicamente lo primero que tenemos que saber sobre los selectores es que hay tres grandes tipos o formas de matchear nuestros tags. Por tag, es decir a todos los tags de un tipo (por ejemplo h1, h2, etc). Por clase (class), es decir a los tags a los que se les haya indicado un estilo determinado (mediante el atributo class). Por id, es decir a un elemento especfico de la pgina segn su id.Ejemplo por tag (ya vimos otro arriba para &lt;span&gt;)td{text-align:center;color:red;}Aplica esas dos propiedades a todos los &lt;td&gt;.filaImpar{text-align:center;color:red;}Este selector, que comienza con un punto, indica que va a matchear con cualquier tag (no importa el tipo de tag), siempre que ste tenga el valor filaImpar en su atributo class. Por ejemplo matcheara con estos tags:&lt;p class="filaImpar"&gt;Hola Soy un P&amp;aacute;rrafo&lt;p&gt;&lt;span class="filaImpar importante"&gt;Hola Soy un Span&lt;p&gt;&lt;tr class="conBordes fondoImportante filaImpar"&gt; &lt;td&gt;Hola, soy una Fila&lt;/td&gt;&lt;tr&gt;Como se ve en el ejemplo anterior, un tag puede tener ms de un class. As los classes no tienen nada que ver con las clases de un lenguaje orientado a objetos. Pueden pensarlos ms bien como labels o etiquetas o marcas que pongo a los tags, para luego por CSS agregarle caractersticas visuales. As eventualmente uno en un proyecto grande, se creara su propia convencin con un conjunto de classes que reutilizara en todo su sitio. Por ejemplo titulo o menu, botonGrande, botonMediano, etc. Es una buena forma de elevar el nivel del html con nuevos significados.El ltimo ejemplo, matchear por id#unElementoEspecifico{text-align:center;color:red;}Este selector es el ms puntual o especfico, y permite matchear con tags, no importa su tipo, ni tampoco su class, sino que solo busca por id.&lt;li id="opcionIrAAyuda"&gt;Ir a Ayuda&lt;/li&gt;&lt;button id="volver"&gt;Volver&lt;/button&gt;Como en una pgina no deberan existir dos tags con el mismo id sin importar en qu tag o nivel se encuentre es el mecanismo menos recomendable para trabajar.Uso de CSS desde HTMLEl html usa el css mediante una declaracin en la seccin HEAD.&lt;html&gt; &lt;head&gt; ... &lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt; ... &lt;/head&gt;&lt;/html&gt;Donde styles.css sera mi archivo de estilos y estara, en este caso en la misma carpeta en que se encuentra este html. Tambin podramos usar una URL absoluta:&lt;link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"&gt;Existen otras formas de incluir estilos en un html, sin embargo la mejor es la que ya citamos. Las dems involucran ensuciar el html, y las pueden ver en este linkCascadaLas reglas se aplican en cascada, esto significa dos cosas: En primer lugar cada componente hereda determinados estilos de sus contenedores, por ejemplo un td (celda de una tabla) hereda los del tr (fila) y del table correspondientes. Los estilos que apliquen al componente especfico sobreescriben a los del contenedor, pero aquellos que no estn especificados se heredan. No todas las indicaciones de estilo son heredables (inheritable en ingls), es importante entender el comportamiento de cada una de las diferentes indicaciones de estilo. En segundo lugar sobre cada componente pueden aplicarse ms de un estilo, que matcheen con ese componente segn su tag, class y id respectivamente. Esos diferentes estilos se van a combinar permitiendo que el estilo ms especfico sobreescriba los estilos ms generales, pero aun manteniendo las indicaciones correspondientes al estilo ms general que no sean redefinidas.Ejemplo de varias reglas aplicando al mismo tiempo sobre un tag.tr{text-align:center;}.resaltar{background-color:red;}Ambas reglas van a aplicar en este tag&lt;tr class="resaltar"&gt; &lt;td&gt;Hola, soy una celda&lt;/td&gt;&lt;/tr&gt;El texto se va a ver centrado y adems con fondo rojo.Combinando Selectores (OR)Es comn que tengamos que aplicar los mismos estilos a diferentes tags. Para evitar duplicacin de cdigo las reglas se pueden combinar. Ej:h1{text-align:center;color:red;}h2{text-align:center;color:red;}p{text-align:center;color:red;}Se puede refactorizar a esto:h1,h2,p{text-align:center;color:red;}La sintaxis entonces es:selector1, selector2, ... selectorN { propiedad1: valor1; propiedad2: valor2; ... propiedadN: valorN;}Se puede pensar como un or. Sera, si es un h1 o es un h2, o es un p.Ventajas del uso de CSSLa separacin de concerns (layout vs. configuracin esttica) permite dos cosas: Configurar y personalizar el estilo que se muestre por usuario/regin/dispositivo y preservar el lema DRY (Dont repeat yourself), la pgina HTML aumenta su expresividad (es ms fcil de entender) los diseadores grficos se concentran el look &amp; feel, decorando los botones, las tablas (grillas), el tipo de letra, los ttulos y tambin los logos, isotipos e imgenes que la aplicacin va a tener. Por lo general reciben un esqueleto de las pginas con datos de prueba escritos en forma manual Por otra parte, los programadores se concentran en la lgica de presentacin y en la facilidad de uso por parte del usuario Links relacionados Temario Algoritmos III" + +} , + +{ + +"title" : "cual es la diferencia entre una tupla y una lista", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/cual-es-la-diferencia-entre-una-tupla-y-una-lista-.html", +"date" : "", +"content" : "En primer lugar vale la pena detenernos a pensar qu queremos modelar al usar tuplas y listas. La tupla representa una agrupacin de valores ordenados, cada uno con un significado particular ya que se intenta modelar una abstraccin compuesta por todos estos elementos. En estructurado podemos compararlas con los registros. Las listas sirven para modelar conjuntos de elementos, para agrupar valores independientes entre s.Tuplas y listas en HaskellUna cosa que suele confundir a la hora de diferenciar listas y tuplas es la idea de que el nmero de componentes de una tupla es fijo, qu quiere decir que es fijo si yo puedo tener 2-uplas, 3-uplas n-uplas?Lo que quiere decir es que las tuplas de distinta aridad son de distinto tipo, es decir no son comparables entre s. Es decir la tupla (a,a) y la tupla (a,a,a) son de tipos distintos y yo no puedo hacer una funcin que acepte ambas tuplas 1.En cambio, las listas s son ambas del mismo tipo ([a]) y entonces s puedo hacer una funcin que funcione en ambos casos.Ejemplos bsicosComencemos por ver qu tipos me dice el Haskell que tiene cada uno de los valores que mencionamos antes:Prelude&gt;:t(True,True)(True,True)::(Bool,Bool)Prelude&gt;:t(True,True,True)(True,True,True)::(Bool,Bool,Bool)Prelude&gt;:t[True,True][True,True]::[Bool]Prelude&gt;:t[True,True,True][True,True,True]::[Bool]Lo que hay que mirar en el ejemplo anterior es que las dos tuplas tienen tipos distintos ((Bool,Bool) y (Bool,Bool, Bool)), mientras que las dos listas tienen el mismo tipo ([Bool]).Adems podemos ver que el tipo de una tupla indica la cantidad de componentes, mientras que el tipo de una lista no eso quiere decir que todas las listas de booleanos son del mismo tipo, independientemente de la cantidad de componentes.Errores de tipoEs fcil ver que si intentamos trabajar con las dos tuplas como si fueran del mismo tipo vamos a tener problemas, un ejemplo sencillo es compararlas por igualdad. Si comparamos las dos listas obtenemos el resultado esperable:Prelude&gt;[True,True]==[True,True,True]Falsepero si intentamos comparar las dos tuplas ocurre un error:Prelude&gt;(True,True)==(True,True,True)&lt;interactive&gt;`:1:15:`` Couldn'tmatchexpectedtype`(Bool,Bool)' `` againstinferredtype`(Bool,Bool,Bool)' `` Inthesecondargumentof`(==)',namely`(True,True,True)' ``Intheexpression:(True,True)==(True,True,True) `` Inthedefinitionof`it':it=(True,True)==(True,True,True) `Uso en funcionesTambin podemos ver que una funcin puede manejar listas de cualquier longitud pero no pasa lo mismo con las tuplas. Si intentamos hacer una funcin todosVerdaderos, con listas es fcil:todosVerdaderosL[]=TruetodosVerdaderosL(x:xs)=x&amp;&amp;todosVerdaderosLxsAl cargar eso en el Haskell obtenemos:Prelude&gt;:ltodosVerdaderos.hs[1of1]CompilingMain(todosVerdaderos.hs,interpreted)Ok,modulesloaded:Main.*Main&gt;todosVerdaderosL[True,True]True*Main&gt;todosVerdaderosL[True,True,True]TruePodramos intentar hacer lo mismo con tuplas, para ello agrego las dos definiciones:todosVerdaderosT(x,y)=x&amp;&amp;ytodosVerdaderosT(x,y,z)=x&amp;&amp;y&amp;&amp;zPero lamentablemente eso no es posible en Haskell:*Main&gt;:r[1of1]CompilingMain(todosVerdaderos.hs,interpreted)todosVerdaderos.hs:5:17:` Couldn'tmatchexpectedtype`(Bool,Bool)' `` againstinferredtype`(a,b,c)' `Inthepattern:(x,y,z)` Inthedefinitionof`todosVerdaderosT': ``todosVerdaderosT(x,y,z)=x&amp;&amp;y&amp;&amp;zFailed,modulesloaded:none.Una forma de definir la funcin es:todosVerdaderosT2(x,y)=x&amp;&amp;ytodosVerdaderosT3(x,y,z)=x&amp;&amp;y&amp;&amp;zeso si pasa los chequeos del haskell:Prelude&gt;:r[1of1]CompilingMain(todosVerdaderos.hs,interpreted)Ok,modulesloaded:Main.Pero vemos que me obliga a usar las funciones separadamente:*Main&gt;todosVerdaderosT2(True,True)True*Main&gt;todosVerdaderosT3(True,True,True)TrueFinalmente, podemos ver que si se intenta intercambiar las funciones se produce un error:*Main&gt;todosVerdaderosT2(True,True,True)&lt;interactive&gt;`:1:18:` Couldn'tmatchexpectedtype`(Bool,Bool)' `` againstinferredtype`(Bool,Bool,Bool)' `` Inthefirstargumentof`todosVerdaderosT2',namely `` `(True,True,True)' `Intheexpression:todosVerdaderosT2(True,True,True)` Inthedefinitionof`it': `it=todosVerdaderosT2(True,True,True)Para ms informacin, ver ac: Pattern_Matching_en_Haskell1 En realidad una funcin s podra recibir tuplas de distinto tipo, si la funcin es polimrfica. Pero eso escapa el objetivo del presente artculo." + +} , + +{ + +"title" : "Cuando usar parentesis", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/cuando-usar-parentesis.html", +"date" : "", +"content" : "A diferencia de matemtica y muchos lenguajes (como C o Java) en Haskell no es necesario utilizar parntesis al pasarle los parmetros a una funcin. Es decir, si tenemos una funcin de un parmetro en matemtica lo escribimos con parntesis: ; mientras tanto, en Haskell, simplemente se pone el parmetro al lado de la funcin .En el caso de tener ms de un parmetro en matemtica estamos acostumbrados a separarlos con comas, por ejemplo: ; en Haskell tampoco se utiliza esa sintaxis. En cambio simplemente se ponen los parmetros uno al lado del otro, separados por espacios:Entonces los parntesis se usan nicamente para Alterar la precedencia Tuplas Usar operadores sin aplicarles todos los parmetros, caso tpico (+) o (+1).Alterar la precedenciaAntes que nada hay que entender qu significa el Concepto de Precedencia en un lenguaje de programacin.Los parntesis permiten naturalmente alterar la precedencia propia del lenguaje, por ejemplo si evaluamos2+3*4obtendremos como resultado 14, ya que la multiplicacin tiene mayor precedencia que la suma; utilizando parntesis podemos alterar ese comportamiento, si escrigimos(2+3)*4podemos lograr que la operacin de suma se ejecute antes que la multiplicacin y obtener 20 como resultado.Para poder utilizar esto eficientemente, hay que tener algn conocimiento de la Precedencia de los operadores ms comunes en Haskell.Ejemplos TBC Tuplas TBC Aplicacin parcial de operadores TBC " + +} , + +{ + +"title" : "Cuestiones basicas para resolver el parcial de objetos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/cuestiones-basicas-para-resolver-el-parcial-de-objetos.html", +"date" : "", +"content" : "Esta es una recopilacin de errores comunes a la hora de resolver un parcial de objetos. Son conceptos muy bsicos, es decir, esto debe considerarse como condiciones necesarias para aprobar el parcial; nunca como condiciones suficientes.Conceptos bsicosUtilizar los conceptos del paradigmaEncontrar abstracciones, aprovechar el polimorfismo, delegar responsabilidades, etc.Hay que programar con objetos, no vale programar como si fuera Algoritmos para aprender eso ya est Algoritmos.Repartir las responsabilidadesQue no me quede todo el cdigo en un mismo objeto. Es fcil verlo (por ejemplo) cuando una caja del diagrama de clases ocupa la mitad de la pgina.Que no todos los mensajes del workspace vayan al mismo objeto.Que no haya un objeto Sistema.Ser consistentePor ejemplo: Si en algn lugar mando un mensaje y trato el resultado como una coleccin debo asegurarme de que la implementacin del mtodo devuelva una coleccin (lo mismo vale para colecciones como para cualquier otro objeto). Si tengo muchos mtodos polimrficos todos deben recibir los mismos parmetros y devolver objetos del mismo tipo. En un mtodo puedo usar las variables de instancia del objeto o los parmetros, cualquier otra variable mgica que aparezca constituye un error.Ser especficoIndicar las relaciones de conocimiento en el diagrama de objetos.Tambin los atributos que tiene cada objeto.Tambin tiene que quedar claro de qu tipo es cada parmetro que espera un mtodo, y qu devuelve.Elegir buenos nombres para clases, mtodos y variablesPor ejemplo diferenciar desde el nombre los mtodos que son rdenes de los que son consultas. Para los primeros conviene usar oraciones en infinitivo o en imperativo. Para las consultas en general usamos el indicativo: camin o caminar podran indicar la orden de realizar una caminata (en el parcial vale poner el acento para que se note la intencin). caminaste podra ser una consulta que devuelve un booleano indicando si camin cuantoCaminaste podra ser una consulta que devuelve una cantidad. Por otro lado, un nombre como caminata dificulta comprender la intencin.Esto es an ms importante si el mtodo en cuestin no est 100% correcto, ya que al menos permite entender lo que quisieron hacer.Cosas bsicas de SmalltalkSi bien no es nuestro objetivo saber bocha de Smalltalk, hay cositas que impactan directamente en la posibilidad o no de comprender lo que estn programando; entonces conviene darles bola:Tienen la gua de lenguajes, senla!Por ejemplo deberan aprovecharla para saber qu mensajes entiende una coleccin, no hace falta acordrselos de memoria para usarlos correctamente.No confundir mensajes con variablesY adems ser bien explcito en el diagrama y en el cdigo, cundo estn enviando un mensaje y cundo estn accediendo a una variable de instancia.La sintaxis es objeto-mensaje-parmetroNo da confundirse con eso!Identificar bien maysculas y minsculas.Los nombres de clase van con mayscula, al igual que las variables de clase.Todo lo dems va en minscula.Romper estas reglas obliga a que el corrector tenga dudas de lo que estn haciendo.El diagrama de clasesDebe ser conexo!No vale slo dibujar las cajitas con los mtodos y atributos, las relaciones entre los objetos son igual de importantes. Una clase que no se relaciona con nadie no aporta a la solucin porque nadie puede mandarle mensajes a sus instancias. Si slo se comunican con otros objetos por parmetros se dibuja una flecha con lnea punteada con la palabrita que parte del receptor del mensaje en cuestin y llega al objeto que se enva por parmetro.Especificar bien las relaciones, diferenciar la herencia de la asociacin o conocimiento.Si la flecha que se usa para los atributos tiene un tringulo en la punta o si la de herencia es una flecha simple est mal!La presentacin del parcialIndicar cmo se usa lo que hicieronPara cada punto del parcial, indicar qu mensaje hay que mandarle a qu objetoEl orden del cdigo es importante a la hora de entender la solucin propuestaEst bueno ordenarlo punto por punto (en contraposicin a juntar todos los mtodos de una misma clase). No solo facilita la correccin sino adems los ayuda a no olvidarse de nadaTambin est bueno ir de lo general a lo particular, es decir, comenzar por el mensaje que se llamara desde el workspace y luego los que se llaman desde ah, as sucesivamente hasta los mensajes ms especficos.ProlijidadHagan buena letra, no amontonen todo, etc.No escribir muy apretadoAs hay lugar para hacer anotaciones y correcciones.OrtografaLos docentes tenemos indicacin explcita del departamento de desaprobar a quienes tengan muchos errores de ortografa, as que pilas con eso.De paso no estara mal practicar un poquito de redaccin, aunque eso va ms que nada para el final.Otras cuestiones importantesNo devolver Strings para informar un error!Los errores se informan con self error.Evitar repeticin de cdigoEn el caso general no est bien tener cdigo repetido; esto suele indicar una falta de abstraccin o bien un problema de asignacin de responsabilidades." + +} , + +{ + +"title" : "Currificacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/currificacion.html", +"date" : "", +"content" : "Cuando hablamos de currificacin nos referimos a que todas las funciones reciben un nico parmetro como mximo. El hecho de que sea posible definir funciones de ms de un parmetro se debe a que son funciones currificadas. Cuando evaluamos por ejemplo, max 4 5, lo que sucede es que se le aplica el nmero 5 a la funcin resultante de aplicarle el 4 a max, o sea que se transforma en (max 4) 5Por eso, cuando escribimos el tipo de una funcin no hay una distincin entre lo que son los parmetros y el valor de retorno, se desdibuja un poco la diferencia. Por ejemplo, el tipo de max puede escribirse de dos formas:max :: (Ord a) =&gt; a -&gt; a -&gt; a --- Forma tradicionalmax :: (Ord a) =&gt; a -&gt; (a -&gt; a) --- Forma currificadaLa segunda denota que max es una funcin de 1 parmetro que retorna una funcin que espera y retorna algo del mismo tipo que lo que ella espera.Esto es lo que permite tener Aplicacin ParcialRelacionando con Expresiones Lambda, cuando las funciones estn currificadas, como pasa con todas las funciones en Haskell, podemos pensar como si hubiera alguien construyendo lambdas de un nico parmetro al rededor de todas nuestras funciones para que las podamos usar como queremos por ejemplo:funcion a b c = ... la lgica de tu funcin ...se traduce a:(&#92;p1 -&gt; (&#92;p2 -&gt; (&#92;p3 -&gt; funcion p1 p2 p3) ) )eso permite que al evaluar funcion parametro, lo que retorna sea una funcin que todava puede ser aplicada 2 veces." + +} , + +{ + +"title" : "Data definiendo nuestros tipos en haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/data--definiendo-nuestros-tipos-en-haskell.html", +"date" : "", +"content" : "Data: qu es y para qu sirveUsamos data para definir un nuevo tipo de dato, por ejemplo si quisiramos definir el tipo Booleano escribiramosdataBooleano=&lt;...&gt; Qu vamos a escribir en &lt;&gt;? los posibles valores que tiene ese tipo separados por un pipe ( ) dataBooleano=Falso|VerdaderoCon esta notacin podramos pensar que el tipo Int est escrito de la siguiente maneradataInt=-2147483648|-2147483647|...|-1|0|1|2|...|2147483647Nota: Int no est definido de esta manera pero sirve para entender el uso de dataSi quisiramos escribir el tipo ColorPrimario cuales seran sus posibles valores?dataColorPrimario=Rojo|Amarillo|AzulSi luego quisiramos hacer una funcin combinar que reciba dos colores primarios distintos y me retorne un color secundario (Naranja, Violeta o Verde), podemos resolverlo usando pattern matching:dataColorSecundario= Naranja | Violeta | Verde combinar :: ColorPrimario -&gt; ColorPrimario -&gt; ColorSecundariocombinar Rojo Amarillo = Naranjacombinar Amarillo Rojo = Naranjacombinar Rojo Azul = Violetacombinar Azul Rojo = Violetacombinar Amarillo Azul = Verdecombinar Azul Amarillo = VerdeCabe mencionar que esto mismo de los colores lo podramos haber hecho con Strings, pero haberlo hecho con data limita los valores posibles a aquellas cosas que consideramos vlidas para el tipo especfico que queremos representar.Tuplas tuplas tuplasUna forma de representar valores que estn compuestos por otros valores, tal que cada uno de ellos tiene una semntica distinta, es usando uno de los tipos compuestos bien conocidos de Haskell, las tuplas.Vamos a hacer un ejemplo con tuplas de 2 elementos por simplicidad, pero lo mismo se aplica para tuplas de n elementos. Supongamos que queremos armar un programa en el cual queremos representar un alumno por su nombre (un String) y sus notas (una lista de Int = [Int]) y tambin queremos representar una pelcula por su ttulo (unString) y los puntajes que le ponen los crticos en imdb (una lista de Int = [Int]). Por ejemplo:cursoK9=[("Federico",[2,3]),("Lder",[10,10,10,10,10]),("Germain",[8,9,10])]pelis=[("Pedornia",[0,0,-3,-666]),("PulpFiction",[9,10,9]),("FightClub",[3,8,8,9,9,10])]Vamos a agregar adems algunas funciones bsicas para interactuar con alumnos y pelculas fcilmente:nombreAlumnounAlumno=fstunAlumnonotasAlumnounAlumno=sndunAlumnotituloPeliculaunaPelicula=fstunaPeliculapuntajesPeliculaunaPelicula=sndunaPeliculaY una de las cosas que queremos hacer con los alumnos es saber si empez mal (si su primer nota no est aprobada):empezoMal=not . aprobada .head. notasAlumnoaprobada nota = nota &gt;= 6Si usamos lo que definimos arriba como un solo programa (un solo .hs), podemos ver que: La funcin nombreAlumno es igual a la funcin tituloPelicula La funcin notasAlumno es igual a la funcin puntajesPeliculaNada me impide consultar:&gt;puntajesPelicula("Lder",[10,10,10,10,10])[10,10,10,10,10]&gt;empezoMal(headpelis)TrueTodo esto es posible porque si miramos los tipos que infiere Haskell no existe diferencia entre una pelcula y un alumno, para Haskell los alumnos y pelculas son slo tuplas de 2 elementos. Ejemplo:&gt;puntajesPelicula([1,2,3],(True,"hola"))(True,"hola")Si definimos un alias de tipo para Alumno y Pelicula de esta forma:type Alumno = (String, [Int])type Pelicula = (String, [Int])Y luego restringimos los tipos de todas las funciones para explicitar que lo que reciben son alumnos o pelculas segn corresponda:nombreAlumno :: Alumno -&gt; StringnombreAlumnounAlumno=fstunAlumnonotasAlumno :: Alumno -&gt; [Int]notasAlumnounAlumno=sndunAlumnotituloPelicula :: Pelicula -&gt; StringtituloPeliculaunaPelicula=fstunaPeliculapuntajesPelicula :: Pelicula -&gt; [Int]puntajesPeliculaunaPelicula=sndunaPeliculaempezoMal :: Alumno -&gt; BoolempezoMal=not . aprobada .head. notasAlumnoDe lo nico que nos salvamos es de consultas como:&gt;puntajesPelicula([1,2,3],(True,"hola"))Porque esa tupla contiene elementos de tipos que no coinciden con los explicitados. Pero esta otra consulta no se ve afectada por el cambio que realizamos, porque tanto Alumno como Pelicula no son ms que (String, [Int]):&gt;empezoMal(headpelis)TrueYa que Haskell es un lenguaje que se fija mucho en los tipos, nos gustara que un caso como los de arriba nos tirar error (donde en vez de mandar un alumno o una pelcula segn corresponda, enviamos cualquier otra cosa incluyendo un alumno donde se esperaba una pelcula y visceversa).Definiendo nuevos tiposPara poder diferenciar a un alumno de una pelcula y a ambos de una tupla, tenemos que definir un nuevo tipo. Eso se hace usando data:dataNuevoTipo=ConstructorTipo1Tipo2...TiponNota: el tipo y el constructor pueden llamarse igual, usaremos nombres distintos a fines didcticos para remarcar en qu contextos lo que usamos es el constructor y en cules el tipo.En nuestro ejemplo:dataAlumno=UnAlumnoString[Int]dataPelicula=UnaPeliculaString[Int]Ahora, para obtener un nuevo alumno o una nueva pelcula, tenemos que usar el ConstructorcursoK9=[UnAlumno"Federico"[2,3],UnAlumno"Lder"[10,10,10,10,10],UnAlumno"Germain"[8,9,10]]--NocambiaempezoMalunAlumno=4&gt;head(notasAlumnounoAlumno)pelis=[UnaPelicula"Pedornia"[0,0,-3,-666],UnaPelicula"PulpFiction"[9,10,9],UnaPelicula"FightClub"[8,8,8,9,9,10]]--AhoraestasfuncionesusanPattern-Matching!nombreAlumno(UnAlumnonombrenotas)=nombrenotasAlumno(UnAlumnonombrenotas)=notastituloPelicula(UnaPeliculanombrenotas)=nombrepuntajesPelicula(UnaPeliculanombrenotas)=notasEs importante remarcar que al hacer esto un alumno o una pelcula YA NO ES UNA TUPLAfst::(a,b)-&gt;anombreAlumno::Alumno-&gt;StringtituloPelicula::Pelicula-&gt;Stringsnd::(a,b)-&gt;bnotasAlumno::Alumno-&gt;[Int]puntajesPelicula::Pelicula-&gt;[Int]cursoK9::[Alumno]empezoMal::Alumno-&gt;Boolpelis::[Pelicula]Ejemplos:A partir de estos valores:fede=UnAlumno"Federico"[2,3]ger=UnAlumno"Germain"[8,9,10]pulp=UnaPelicula"PulpFiction"[9,10,9]Veamos qu sucede al hacer algunas consultas sobre funciones que esperan tuplas, alumnos o pelculas.&gt;fst fedeError(fstesperaunatuplayfedeesde tipo Alumno)&gt;nombreAlumnofede"Federico"&gt;nombreAlumnopulpError(nombreAlumnoesperaalgo de tipoAlumnoypulpesde tipo Pelicula)&gt;puntajesPeliculafedeError(puntajesPeliculaesperaPeliculayfedeesdetipo Alumno)&gt;puntajesPeliculapulp[9,10,9]&gt;empezoMalfedeTrue&gt;empezoMal(headpelis)Error(empezoMalesperaAlumnoyelprimerelementodepelisesde tipo Pelicula)Derivar typeclassesEs muy comn querer comparar por igualdad y mostrar por pantalla un valor que tiene un tipo definido por nosotros.&gt;headcursoK9Error(AlumnonotienelarestriccinShow)Para que esto funcione deberamos: Decir que Alumno es un tipo que pertenece a la restriccin Show Definir la funcin show para un AlumnoEn vez de hacer esto a mano (agregando una instancia de la typeclass como se explica ms adelante), y gracias a que los elementos que forman un Alumno SI tienen la restriccin Show, podemos hacer que el Alumno derive esa restriccin--Lonicoquehayqueagregaresderiving(Show)dataAlumno=UnAlumnoString[Int]deriving(Show)Con este agregado podemos hacer&gt;headcursoK9UnAlumno"Federico"[2,3]Ahora, si hacemos lo siguiente&gt;fede==gerError(elAlumnonotienelarestriccinEq)Tambin parece comn querer preguntar si dos alumnos son iguales (o distintos), pasa lo mismo que con Show, nos gustara que el Alumno pertenezca a la typeclass Eq.--Lonicoquehayqueagregaresderiving(Show,Eq)dataAlumno=UnAlumnoString[Int]deriving(Show,Eq)Con este agregado podemos hacer:&gt;fede==gerFalse&gt;UnAlumno"Roberto"[7,8,9]==UnAlumno"Huberto"[7,8,9]False&gt;UnAlumno"Roberto"[7,8,9]==UnAlumno"Roberto"[7,8,9]TrueTambin se puede utilizar el deriving con la clase OrddataNota=Insuficiente|Regular|Bien|MuyBienAl hacer:Main&gt;Insuficiente&gt;RegularERROR:Noinstancefor(OrdNota)Esto se debe a que el tipo Nota no cumple con la restriccin Ord, por defecto se considera a los valores en forma ascendente de izquierda a derecha (i.e. Insuficiente &lt; Regular &lt; Bien &lt; MuyBien).Para obtener este comportamiento en los valores del tipo Nota lo nico que debemos hacer es derivar la restriccin OrddataNota=Insuficiente|Regular|Bien|MuyBienderivingOrdMain&gt;Insuficiente&gt;RegularFalseLo mismo podra hacerse con los tipos ColorPrimario y ColorSecundario definidos anteriormente en este artculo. De seguro vamos a querer que puedan mostrarse. Con derivar Show para ColorSecundario sera suficiente para poder usar la funcin combinar :: ColorPrimario -&gt; ColorPrimario -&gt; ColorSecundario desde la consola y ver el resultado, pero a su vez poder ver los colores primarios suena como algo deseable.Tambin podemos sacarle provecho a derivar Eq, lo que nos permitir llegar a esta nueva solucin sin repeticin de lgica:dataColorPrimario=Rojo|Amarillo|Azul deriving (Show, Eq)dataColorSecundario= Naranja | Violeta | Verde deriving (Show, Eq)combinar :: ColorPrimario -&gt; ColorPrimario -&gt; ColorSecundariocombinar Rojo Amarillo = Naranjacombinar Rojo Azul = Violetacombinar Amarillo Azul = Verdecombinar color1 color2 | color1 /= color2 = combinar color2 color1Data con Record SyntaxEs muy comn hacer funciones para obtener los valores que forman nuestro individuo compuesto como hicimos con las pelculas y los alumnos.Imaginen que ahora queremos agregarle a nuestro tipo Pelicula (adems del nombre y sus puntajes), el nombre del director, el nombre de los actores principales y el ao en que se estren.dataPelicula=UnaPeliculaStringString[String]Int[Int]Lo primero que notamos es que no es tan fcil identificar cada elemento. Para eso existe la posibilidad de declarar sinnimos de tipo usando type. En el ejemplo de las pelculas podemos hacer algo como:typeTitulo=StringtypeNombreDirector=StringtypePuntajes=[Int]dataPelicula=UnaPeliculaTituloNombreDirector[String]IntPuntajesderiving(Show,Eq)narnia=UnaPelicula"Pedornia""AndrewAdamson"["TildaSwinton","GeorgieHenley","WilliamMoseley"]2005[0,0,-3,-666]pulp=UnaPelicula"PulpFiction""QuentinTarantino"["JohnTravolta","UmaThurman","SamuelL.Jackson"]1994[9,10,9]fc=UnaPelicula"FightClub""DavidFincher"["BradPitt","EdwardNorton","HelenaBonhamCarter"]1999[8,8,8,9,9,10]Lo cual mejora un poco la expresividad de la definicin. Igualmente a la hora de construir el dato tenemos que tener cuidado de no pasar primero el nombre del director y luego el ttulo, porque al fin y al cabo los dos son de tipo String, y por ende va a tipar una construccin incorrecta en base a nuestro dominio.Otro tema es que tenemos que definir nuevamente funciones como tituloPelicula y puntajesPelicula:tituloPelicula(UnaPeliculanombredirectoractoresanioEstrenonotas)=nombrepuntajesPelicula(UnaPeliculanombredirectoractoresanioEstrenonotas)=notasComo en cualquier otro programa, las variables que no nos interesan en absoluto pueden ser reemplazadas por la variable annimatituloPelicula(UnaPeliculanombre____)=nombrepuntajesPelicula(UnaPelicula____notas)=notasLgicamente tambintenemosquedefinirfuncionesparaelrestodeloscampos que antes no existan:directorPelicula(UnaPelicula_director___)=directoractores(UnaPelicula__actores__)=actoresanioEstreno(UnaPelicula___anio_)=anioUna forma ms rpida de definir este tipo de funciones es usando la sintaxis de registro (disponible en GHC, no en Hugs).En vez de definir slo los tipos de los valores que van a estar en la pelcula, tambin agregamos en la definicin el nombre de la funcin por el cual queremos obtener dicho valor.Alutilizarlanotacinderegistrohayque definir los campos que lo componen de una forma distinta, tenemos que: encerrarladefinicindeloscamposentrellaves{} separarcadacampousandocomas indicar el nombre y de qu tipo es cada campodataPelicula=UnaPelicula{tituloPelicula::String,directorPelicula::String,actores::[String],anioEstreno::Int,puntajesPelicula::[Int]}deriving(Show,Eq)Con esta definicin automaticamente Haskell define por nosotros las funciones tituloPelicula, puntajesPelicula, directorPelicula, actores y anioEstreno. El dominio de cada una de estas funciones es Pelicula y retornan lo que corresponda en cada caso.Adems cuando querramos obtener una nueva Pelcula, podemos hacerpulp=UnaPelicula"PulpFiction""QuentinTarantino"["JohnTravolta","UmaThurman","SamuelL.Jackson"]1994[9,10,9]O bien podemos usar la siguiente notacin que slo es vlida para datas definidos de esta forma. Como se puede ver, es ms claro a que campo pertenece cada valor y no es necesario seguir un orden en los valores mientras se indique a que campo pertenecepulp=UnaPelicula {tituloPelicula="PulpFiction",directorPelicula="QuentinTarantino",anioEstreno=1994,puntajesPelicula=[9,10,9],actores=["JohnTravolta","UmaThurman","SamuelL.Jackson"]}Esto ayuda mucho a la expresividad, pero tambin es ms verboso. Uno tiene que evaluar cundo vale la pena y cundo no.Otra cosa simptica de definir el data con sintaxis de registro es que que si el tipo deriva la typeclass Show, lo que se imprima en la consola cuando la expresin evaluada retorna algo de nuestro tipo (Pelicula en este caso) ser ms fcil de entender, porque mostrar cada valor asociado al nombre del campo en vez de uno al lado del otro, independientemente de qu notacin se use para crear la pelcula en cuestin.Finalmente algo ms que nos da esta forma de definir el data es un azcar sintctico para facilitar el copiado de datos, lo cual es particularmente til para trabajar de forma inmutable. Las siguientes definiciones son equivalentes:agregarPuntaje nuevoPuntaje (UnaPelicula titulo director anio puntajes actores) = UnaPelicula titulo director anio (nuevoPuntaje : puntajes) actores agregarPuntaje' nuevoPuntaje pelicula = pelicula { puntajesPelicula = nuevoPuntaje : puntajesPelicula pelicula }En ambos casos lo que se est haciendo es crear una nueva pelcula que tiene la misma informacin que la que se recibi por parmetro, excepto por los puntajes donde indicamos cules deberan ser los puntajes de la nueva pelcula. De ninguna forma se modificarn los puntajes de pulp si consultamos agregarPuntaje' 10 pulp.IMPORTANTE! Tengan en cuenta al usar este feature de copiado de ser cuidadosos y no abusar (al igual que no debera abusarse del pattern matching) porque un uso demasiado extendido atenta contra las abstracciones pequeas y reutilizables. Funciones chiquitas y reutilizables matan sintaxis cheta.Cmo instanciar una typeclassYa dijimos que a cada restriccin se la conoce como typeclass. A cada tipo que pertenece a una typeclass se le debe definir una instancia de la misma.Por ejemplo la clase Eq en algn lugar del Prelude (la biblioteca standard de Haskell) puede estar definida as:--EstoyavieneconHaskellclassEqawhere(==),(/=)::a-&gt;a-&gt;Bool--LasinstanciasdeEqdebendefiniralmenosunadeestas2operaciones(/=)xy=not(x==y)(==)xy=not(x/=y)Si decimos que el tipo Bool pertenece a la clase Eq escribimos--EstoyavieneconHaskellinstanceEqBoolwhere(==)TrueTrue=True(==)FalseFalse=True(==)__=FalseOtro ejemplo con la clase Ord--NotarqueatienelarestriccinEqenladefinicindelaclaseOrdaclassEqa=&gt;Ordawhere(&lt;)::a-&gt;a-&gt;Bool(&lt;=)::a-&gt;a-&gt;Bool(&gt;)::a-&gt;a-&gt;Bool(&gt;=)::a-&gt;a-&gt;Boolmax::a-&gt;a-&gt;amin::a-&gt;a-&gt;aSi queremos hacer que el tipo Pelicula sea instancia de la clase Ord (por poner un ejemplo, definimos la funcin (&gt;) para que nos diga que una pelcula es mayor que otra si su promedio de puntajes es mayor), podemos escribir:instanceOrdPeliculawhere(&gt;)unaPeliculaotraPelicula=promedio(puntajesPeliculaunaPelicula)&gt;promedio(puntajesPeliculaotraPelicula)Por lo general es suficiente con derivar typclasses en nuestros data, pero es importante recordar que para poder hacer esto, todos los componentes del data a su vez deben pertenecer al typeclass que estamos derivando. Y si en algn momento nos pasa que tenemos un data que se compone, entre otras cosas, por alguna funcin, ya no vamos a poder derivar as como as Show y Eq que son las ms usuales, porque las funciones no son ni Show ni Eq.En esos casos podemos o bien optar porque nuestro data no sea Show o Eq, o bien definir un instance para esta typeclass que se corresponda con nuestro tipo de dato y as determinar nuestra propia solucin a ese problema.Supongamos que queremos mostrar a nuestros alumnos de una forma distinta, que nos muestre el nombre, las notas y adems nos diga el estado de cursada (si aprob o no en base a sus notas). Necesitamos agregar un instance para Show Alumno en vez de derivar Show. Por ejemplo:instance Show Alumno where show (UnAlumno nombre notas) = show nombre ++ ": " ++ estadoDeCursada notas ++ " con " ++ show notas estadoDeCursada notas | all aprobada notas = "CURSADA APROBADA" | otherwise = "CURSADA DESAPROBADA"Mltiples constructores por tipoSupongamos que nos interesa saber la densidad de un cuerpo. Por ahora vamos a manejar cilindros (de los cuales sabemos su masa, su altura y el radio de su base), cubos (slo conocemos su masa y el largo de alguno de sus lados) y esferas (de ellas se conoce su masa y su radio).Para calcular la densidad de un cuerpo vamos a utilizar la siguiente frmula: densidad=masa/volumen.Arranquemos por declarar el tipo de dato para representar un cuerpo:dataCuerpo=Cilindro{masa::Float,altura::Float,radio::Float}|Cubo{masa::Float,lado::Float}|Esfera{masa::Float,radio::Float}deriving(Show,Eq)Podemos ver que el tipo Cuerpo incluye los constructores Cilindro, Cubo y Esfera. Como la frmula de la densidad es igual para todos los cuerpos podemos escribir:densidadunCuerpo=masaunCuerpo/volumenunCuerpoAhora bien, el clculo del volumen es algo particular para cada cuerpovolumen(Cilindro_unaAlturaunRadio)=pi*unRadio*unaAlturavolumen(Cubo_unLado)=unLado**3volumen(Esfera_unRadio)=4/3*pi*(unRadio**3)" + +} , + +{ + +"title" : "Declaratividad vs expresividad", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/declaratividad-vs--expresividad.html", +"date" : "", +"content" : "Muchas veces mencionamos los conceptos de Declaratividad y Expresividad, pero cuando corresponde hablar de uno o del otro? Y como se relacionan con otros conceptos vistos en la materia? Veamoslo con algunos ejemplos:sumar una lista de nmeros ns Solucin 1 (utiliza el concepto de orden superior):foldl(+)0ns Solucin 2 (no utiliza el concepto de orden superior):sumnsLa solucin 2 es ms declarativa que la solucin 1 ya que en la solucin 1 hay que saber:que se suma con la funcin (+)cmo se define el valor inicial del acumulador (0)En la solucin 2 estos detalles no existenEntonces: Siempre que se hable de ms o menos declarativo comparen cosas, no digan ms declarativo al aire Una solucin A es ms declarativa que una solucin B si: A tiene menos detalles algortmicos que B Esto significa que la nocin de algortmo/secuencia de pasos/definicin del cmo lo hace sea menor en A que en B As como pasa con orden superior y declaratividad, pasa con la idea de polimorfismo y declaratividad.Otra cualidad que remarcamos en las soluciones es la expresividad, decimos que una solucin A es ms expresiva que una solucin B si la solucin A se entiende ms rpido/es ms fcil de leer que la solucin B.Claramente la idea de expresividad puede verse de forma subjetiva.Volviendo a las soluciones para sumar una lista de nmeros Solucin 3sumar[]=0sumar(x:xs)=x+sumarxsAlguien puede decir que la solucin 1 es ms expresiva que la solucin 2 (porque le gusta el foldl y lo entiende) pero en la primer clase de funcional si te muestran (sin explicar) entre la solucin 1 y la solucin 2 es muy probable que la solucin 2 pasara a ser la ms expresiva. En contraste, para alguna persona retorcida la solucin 3 puede ser la ms expresiva .A lo que vamos con esto es que, la idea de declaratividad debera ser ms objetiva que la idea de expresividad.De todas formas, con la debida justificacin y relacionndolo con el ejercicio del final, se puede hablar de ambos conceptos. Por lo general, las soluciones ms declarativas resultan a su vez ms expresivas, pero dejando las subjetividades a un lado, un cdigo imperativo bien hecho puede resultar ms legible que uno declarativo con nombres de operaciones y variables mal puestos.Declaratividad, expresividad y abstraccinEs importante no confundir los trminos de expresividad, abstraccin y declaratividad. Aunque estn muy relacionados entre s, son tres conceptos diferentes, que bien pueden darse por separado.Como decamos antes, la relacin que con ms frecuencia vamos a encontrar es que un cdigo declarativo tiende a ser ms expresivo que uno imperativo, ya que puedo leer directamente de qu se trata el problema, en lugar de deducir qu es lo que un algoritmo est tratando de resolver.Ejemplo en pseudocdigo:IntegercuantosPares(Arrayns){Integeri;Integeracum=0;for(i=0;i&lt;longitudDelArray(ns);i=i+1){if(ns[i]mod2==0){acum=acum+1;}}returnacum;}Esta funcin de por s representa una abstraccin: es una operacin que puedo utilizar cada vez que necesite saber la cantidad de nmeros pares hay en el array que se recibe por parmetro. Gracias a que tiene un nombre apropiado (detalle que aumenta la expresividad), podra no tener que leer el cdigo para saber qu es lo que hace.Leyendo el cuerpo de la funcin, podemos tratar de encontrar otra abstraccin ms. En el contexto de la funcin cuantosPares, qu significa este fragmento?if(ns[i]mod2==0){acum=acum+1;}Podemos entender que se est evaluando si ns[i] (el elemento del array que est en la posicin i) es mltiplo de 2, y si esto es cierto contamos un par ms. Una abstraccin podra ser una funcin que evale si un nmero (en este caso ns[i]) es mltiplo de otro (en este caso 2). El cdigo cambiara a:if(esMultiploDe(ns[i],2)){acum=acum+1;}Al encontrar una abstraccin y ponerle nombre, hace que mi cdigo quede ms expresivo. Pero recordemos que hacamos esto para saber si ns[i] era par. Cuando evaluamos la funcin esMultiploDe con 2 como segundo argumento, estamos justamente preguntando si ns[i] es par.Teniendo en cuenta esto, podramos tener directamente la abstraccin esPar, i.e. una funcin que recibe un solo argumento (un nmero) y me dice si ese nmero es par o no. Por otro lado, si estamos contando pares, la variable acum bien podra llamarse cantidadDePares. Entonces el cdigo podra quedar as:if(esPar(ns[i])){cantidadDePares=cantidadDePares+1;}Podemos ver que un componente esencial de la expresividad puede ser el elegir buenos nombres para los elementos de mi cdigo (variables, funciones, procedimientos, etc).Haber encontrado estas abstracciones ayud a que el cdigo quede ms expresivo, ya que una se entiende ms rpido lo que hace esPar(ns[i]) en comparacin con esMultiploDe(ns[i],2) o con ns[i] mod 2 == 0.Ahora el cdigo expresa que un nmero tiene que ser par en vez de exponer el algoritmo o las operaciones matemticas necesarias para saber si el mdulo de la divisin por 2 es 0. Esta ltima solucin est ms cerca de qu quiero resolver en vez de cmo pretendo resolverlo." + +} , + +{ + +"title" : "Declaratividad", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/declaratividad.html", +"date" : "", +"content" : "La declaratividad es una caracterstica de algunas herramientas que permiten o fuerzan la separacin entre el conocimiento del dominio de un programa y la manipulacin de dicho conocimiento. Dichas herramientas pueden ser de diversa naturaleza, tanto prcticas como lenguajes, entornos, frameworks, etc o conceptuales como paradigmas o arquitecturas.El concepto de declaratividad se contrapone a la tradicional programacin imperativa en la cual el conocimiento y la lgica se encuentran muchas veces mezclados dentro de la misma porcin de cdigo resultando difcil determinar donde comienza uno y dnde termina el otro.Las herramientas declarativas permiten muchas veces un ms alto grado de reutilizacin y de abstraccin en tareas repetitivas y por eso la declaratividad es hoy en da una caracterstica fundamental en muchos entornos de programacin para sistemas de mediana o gran envergadura, ya que es una herrramienta importante para organizar y simplificar la construccin de un sistema complejo.Conocimiento y manipulacinEn un programa construido de forma declarativa se produce una separacin entre la descripcin del problema por un lado y los algoritmos o estrategias para encontrar la solucin por el otro.Un error comn es hablar de la separacin entre el qu y el cmo. Si bien esta idea puede servir como una primera aproximacin al concepto, en realidad cualquier funcin - predicado - mtodo - procedimiento puede verse como una separacin entre el qu (dado por el nombre de la funcin, lo nico que necesita saber el invocador) y el cmo (la implementacin de la funcin).En un programa imperativo suelen estar mezcladas la descripcin del problema con la estrategia de resolucin, a tal punto que muchas veces es difcil de detectar cul es el problema que se est tratando de solucionar.Para verlo mejor es conveniente bajar a un ejemplo, para eso vamos a pensar en el sistema de correlatividades de la facultad. Pensando imperativamente, el algoritmo de solucin sera algo as: A partir de un alumno obtener la carrera que est cursando y con eso las materias de esa carrera, almacenarlas en una variable auxiliar. Eliminar de esa coleccin de materias aquellas que el alumno ya haya cursado. Recorrer la lista de las materias restantes y para cada una: Obtener su lista de corelativas Recorrerla y para cada correlativa verificar si el alumno curs esa materia En caso de no haberla cursado, eliminar la materia de la coleccin auxiliar Las materias que quedaron en la coleccin son las que se pueden cursar.En cambio, la definicin declarativa eliminar todos los conceptos programticos como variables auxiliares, recorrer colecciones o ir eliminando elementos de la coleccin. Ms an, la versin declarativa no tendr un concepto de orden, simplemente intentar describir el problema de la forma ms abstracta posible, solamente tratando de contestar la pregunta, qu materias puede cursar un alumno? Un alumno puede cursar las materias de su carrera que no haya cursado an y cuyas correlativas s haya cursado.En este punto seguramente se preguntarn si es posible hacer un programa que exprese solamente eso, sin toda la lgica adicional necesaria, bueno aqu est el cdigo prolog que dice exactamente eso: puedeCursar(Alumno, Materia):- carrera(Alumno, Carrera), materia(Carrera, Materia), % Es una materia de la carrera del alumno not(curso(Alumno, Materia)), % No curs la materia forall(correlativa(Materia, Corr), curso(Alumno, Corr)). % Curs todas las correlativasElementos en un programa declarativoUn programa declarativo separa claramente los siguientes elementos: El objetivo El conocimiento El motor que manipula el conocimiento para lograr el objetivo deseadoEn el ejemplo anterior, el objetivo es la consulta realizada sobre qu materias puede cursar un alumno. El conocimiento es la informacin que se encuentra en la base de conocimiento sobre las materias disponibles en la carrera y cules ya curs el alumno en cuestin. El motor de Prolog toma el conocimiento y resuelve la consulta realizada en base al programa y deduce todas las posibles relaciones que la satisfagan.El mecanismo utilizado por el motor de Prolog llamado Backtracking prueba todas las posibilidades para solucionar el problema, no hace falta programar este algoritmo para cada problema particular, con lo cual podemos concentrarnos exclusivamente en el objetivo de nuestro programa y no en la complejidad algortmica general que permite procesar la informacin.Declaratividad en los distintos paradigmasDentro de los paradigmas vistos, el paradigma funcional y el lgico tienen una naturaleza declarativa. Eso no quiere decir que no se pueda ser declarativo programando bajo el marco de otro paradigma, de la misma forma en que se puede programar de forma poco declarativa en lgico y funcional (por ejemplo, la recursividad no es una herramienta muy declarativa que digamos).A medida que logramos abstraer nuestros problemas podemos armar nuestros propios motores que nos permitan trabajar de forma ms declarativa.Herramientas declarativas en el mundo realEl lenguaje SQL para trabajar con bases de datos relacionales es un claro ejemplo de declaratividad que se usa ampliamente en la indusria.Los motores de bases de datos, a partir de consultas provistas por el usuario que especifican el origen de los datos (FROM), los filtros a aplicar sobre los posibles resultados (WHERE), las transformaciones a realizar sobre las filas resultantes (SELECT) y criterios de ordenamiento (ORDER BY) por ejemplo, realizan bsquedas complejas relacionando las tablas de origen solicitadas de la forma ms optimizada posible en base a los ndices que el usuario defina y estadsticas que el mismo motor realiza.El algoritmo utilizado por el motor est muy separado del conocimiento (qu entidades existen, cmo se relacionan entre ellas), lo cual permite al usuario abstraerse de esta lgica de bsqueda y concentrarse exclusivamente en el modelado de datos." + +} , + +{ + +"title" : "Definiciones locales where", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/definiciones-locales--where-.html", +"date" : "", +"content" : "Hay ocasiones en las cuales nuestras funciones tienen una complejidad que puede disminuirse definiendo funciones ms chicas que la componen, pero las mismas no son de particular inters fuera del contexto de esa funcin. Una forma de definir funciones que slo se encuentran definidas en el contexto de una funcin es usando where.Supongamos que queremos hacer una funcin que nos dice el estado de gordura de una persona y sabemos que esto se determina a partir de la altura y el peso de la mismagordurapesoaltura|peso/altura^2&lt;=18.5="Desnutrido"|peso/altura^2&lt;=25.0="Normal"|peso/altura^2&lt;=30.0="Gordito"|otherwise="Obeso"Podemos ver que la expresin peso / altura ^ 2 se repite y sera bueno extraerlo a una funcin, pero para el resto del programa del mdico clnico no tiene ninguna utilidad. Una forma elegante para definir la funcin gordura es mediante definiciones locales dndole un nombre a esta expresin.gordurapesoaltura|indiceGordura&lt;=18.5="Desnutrido"|indiceGordura&lt;=25.0="Normal"|indiceGordura&lt;=30.0="Gordito"|otherwise="Obeso"whereindiceGordura=peso/altura^2Algo simptico, como se ve en este ejemplo, es que podemos usar los argumentos de la funcin global en la local como si fueran constantes. Si quisiramos poder variar los valores tambin es posible parametrizar a la funcin local como cualquier otra funcin.holaDonesdon1don2=saludardon1++saludardon2wheresaludaralguien="HolaDon"++alguien++"!"Nota: Al igual que con las guardas, para que el where funcione hay que dejar al menos un espacio de indentacin" + +} , + +{ + +"title" : "Deploy en maven central", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/deploy-en-maven-central.html", +"date" : "", +"content" : "Ests desarrollando un proyecto Maven para Uqbar -el cual tiene como pom padre uqbar-parent-project- y ahora lo quers desplegar en Maven Central, que hacer?Tenemos 2 tareas para hacer: preparar el release y luego publicarlo. La primera s o s vas a tener que hacerla en tu PC, porque vos sos responsable de, por ejemplo, elegir la versin de este nuevo release. Veamos entonces cmo hacer esto:Preparar el release Creamos el release$mvn--batch-moderelease:cleanrelease:prepareEste comando crea un commit y un tag para la nueva versin y luego otro commit agregandole nuevamente el -SNAPSHOT a la versin. La opcin batch-mode hace que el plugin no pregunte la versin y asuma la correlativa a la actual, puede omitirse si se quiere especificar otra versin (siempre siguiendo los lineamientos planteados por Semantic Versioning). Verificamos que todo est bien$gitlog#deberiahaberdoscommitsnuevos$gittag-l#deberiahaberuntagnuevo$gitstatus#nodeberaquedarnadasincommitearSi quedaron cambios sin commitear pods agregarlos al ltimo commit$gitcommit--amend--no-edit Pusheamos los 2 commits nuevos y el tag$gitpush--follow-tagsY con esto ya tendremos en nuestro repositorio GitHub todo lo necesario para publicar el nuevo release.Publicar el releaseEste punto va a depender de cmo est configurado el repositorio. Si bien configurada la integracin continua via Travis, entonces no tens que hacer ms nada. Por las dudas, entr a Travis y fijate que se est buildeando el tag que acabs de subir (esto pods verlo en la parte de Branches).Si no tiene configurado Travis, entonces tens dos opciones: Configurarlo vos :). No es difcil y tenemos una gua de cmo hacerlo en el blog de Uqbar (prximamente). Hacerlo a mano. Ten en cuenta que para esto tens que tener una cuenta en Sonatype autorizada para subir artefactos de Uqbar y toda la configuracin necesaria para que funcione (firma GPG publicada - hay un paso a paso en esta pregunta de Stack Overflow, credenciales en el settings.xml, etc), lo cual te va a llevar ms tiempo que configurar el CI. Si igualmente quers hacerlo, los pasos son estos: Nos paramos en el tag que acabamos de crear$gitcheckout[nombredelrelease,porejemplov3.3] Publicamos el release en Sonatype$mvncleandeploy-Prelease#{ponerlapwddeOSS:} (Opcional) Volvemos a master para seguir trabajando$gitcheckoutmaster" + +} , + +{ + +"title" : "Deploy componentes Uqbar", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/deploys-componentes-de-dominio-uqbar.html", +"date" : "", +"content" : "Componentes de dominio UqbarMotivacinLos componentes de dominio uqbar estn pensados para trabajar exclusivamente el modelo de negocio de los ejemplos y poder reutilizarlos en diferentes tecnologas, ya sea de UI (Arena, Wicket, incluso Android) o de lenguajes base (podramos definir el conversor en Java y generar la UI en Arena programndola en Scala, Xtend o Groovy)Configuraciones de Maven necesariasParent-projectEl proyecto padre debe ser uqbar-examples-parent/ para proyectos Java uqbar-examples-xtend-parent/ para proyectos XtendCualquiera de estos proyectos padre estn deployados en el repositorio Maven de Uqbar, que est situado enhttp://uqbar-wiki.org/mvn/releasesDependenciasEn el pom debemos tener dependencias hacia uqbar-domain (la versin correspondiente)y no es necesario nada ms.Los objetos de dominio deben anotarse como Observable para que funcionen en Arena, y respetar la convencin Java Bean de tener un constructor vaco y getters/setters.RepositoriosDado que el proyecto padre no est en Maven Central, debemos agregar los repositorios maven de Uqbar en forma manual: &lt;repositories&gt; &lt;repository&gt; &lt;id&gt;uqbar-wiki.org-releases&lt;/id&gt; &lt;name&gt;uqbar-wiki.org-releases&lt;/name&gt; &lt;url&gt;http://uqbar-wiki.org/mvn/releases&lt;/url&gt; &lt;/repository&gt; &lt;repository&gt; &lt;snapshots /&gt; &lt;id&gt;uqbar-wiki.org-snapshots&lt;/id&gt; &lt;name&gt;uqbar-wiki.org-snapshots&lt;/name&gt; &lt;url&gt;http://uqbar-wiki.org/mvn/snapshots&lt;/url&gt; &lt;/repository&gt; &lt;/repositories&gt;Esto es para que el build de travis no falle.Deploy de una nueva versinDado que no tenemos CI en este tipo de ejemplos, debemos manualmente Definir la versin del ejemplo, por caso el conversor podra pasar de 1.0.5-SNAPSHOT a 1.0.5 Hacer un commit + push al repositorio git Una vez que est el ok de Travis en la lnea de comando ejecutar$ mvn clean deploy Esto agregar el componente en http://uqbar-wiki.org/mvn/releases. Por ltimo, conviene subir la versin del ejemplo a 1.0.6-SNAPSHOT, para estar seguros de no subir un release.A futuro esperamos contar con un esquema de CI que facilite las cosas." + +} , + +{ + +"title" : "Desafio Construir esta sucesión", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/desafio--construir-esta-sucesion.html", +"date" : "", +"content" : "Utilizando recursividad en Haskell, obtener la siguiente secuencia:111211211111221312211etc..." + +} , + +{ + +"title" : "Desafio find con notacion point free", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/desafio--find-con-notacion-point-free.html", +"date" : "", +"content" : "Se desea definir la funcin find, que dado un criterio y una lista encuentra al primero que lo cumple:Main&gt;findeven[1,35,36,9]36El objetivo es definirla as:find=.........O sea, con notacin point-free para ambos parmetros, sin usar expresiones lambda ni funciones auxiliares.Como la solucin puede obtenerse probando un poco, para que la respuesta al desafo sea aceptada, debe ir acompaada de una pequea explicacin de cmo funciona." + +} , + +{ + +"title" : "Desafio hacer que un data propio sea enum", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/desafio--hacer-que-un-data-propio-sea-enum.html", +"date" : "", +"content" : "Hacer que estas consultas funcionen exactamente as:Main&gt;[CPersona"a"1..CPersona"c"1][CPersona"a"1,CPersona"b"1,CPersona"c"1]Main&gt;[CPersona"f"1..CPersona"k"1][CPersona"f"1,CPersona"g"1,CPersona"h"1,CPersona"i"1,CPersona"j"1,CPersona"k"1]Pistas: Hay que hacer que el tipo Persona pertenezca a la clase Enum. Para ello hay que usar la instruccin instance y definir dos funciones. Ac hay un ejemplo de cmo estn definidos los tipos bsicos y sus typeclasses." + +} , + +{ + +"title" : "Desafio ordenar con árbol B", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/desafio--ordenar-con-arbol-b.html", +"date" : "", +"content" : "Implementar en Haskell un rbol binario y utilizarlo para ordenar una listaPista: ver ejemplo en ejemplo data multiples constructores.hs" + +} , + +{ + +"title" : "Desafio pirámide de números", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/desafio--piramide-de-numeros.html", +"date" : "", +"content" : "Dada la siguiente pirmide (cortada) con 9 casilleros (5 en la base + 4 en la cima):Se quieren acomodar los nmeros del 1 al 9 donde cada casillero de la cima sea igual a la suma de los 2 casilleros que tiene como base. Un ejemplo chiquito podra ser:El desafo consiste en encontrar todas las soluciones posibles para acomodar los nmeros del 1 al 9 en la pirmide.Ayuda: Existe el predicado between(Inicio, Fin, Numero) el cual dado un nmero Inicio y un nmero Fin relaciona algn Numero que se encuentra entre esos otros dos." + +} , + +{ + +"title" : "Desafio suma de distancias", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/desafio--suma-de-distancias.html", +"date" : "", +"content" : "Parte 1Escribir el cdigo necesario (en donde sea necesario) para poder ejecutar en un workspace:1kilometros+20metrosy que al imprimir (print it) el resultado, se obtenga:1020metrosClaramente debe funcionar tambin para otros nmeros que no sean el 1 y el 20.Parte 2Hacer que funcione cualquier combinacin:3metros+400metros+2kilometros"alimprimirloimprime2403metros"" + +} , + +{ + +"title" : "Desafio Suma Par", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/desafio--suma-par.html", +"date" : "", +"content" : "sumaPar :: Number -&gt; Number -&gt; BoolsumaPar = f.(+) Definir f para que la funcin diga si la suma de dos nmeros da un nmero par. Explicar el tipo de f y por qu se puede componer con la funcin (+)." + +} , + +{ + +"title" : "Desafio triada uqbariana", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/desafio--triada-uqbariana.html", +"date" : "", +"content" : "Llamamos triada a cualquier conjunto de 3 nmeros { x; y; z }. En particular nos enfocaremos en las triadas uniformes que son cualquier conjunto de 3 nmeros iguales { x; x; x }.Decimos que una triada se aparenta a un nmero N si existe alguna forma de operar los tres nmeros de la triada de modo que el resultado sea N.Por ejemplo, la triada { 2; 2; 2 } se aparenta al 3 porque 2 + 2 / 2 = 3 la triada { 1; 1; 1 } se aparenta al 2 porque (1 + 1) * 1 = 2Las restricciones para operar la triada son: No se permite agregar ms nmeros Solamente usaremos las operaciones bsicas: { +; -; *; /; }, ninguna msPor ltimo, definiremos las triadas uqbarianas como todas las triadas uniformes que van del 1 al 9, o sea:{ 1; 1; 1 }{ 2; 2; 2 }{ 3; 3; 3 }{ 4; 4; 4 }{ 5; 5; 5 }{ 6; 6; 6 }{ 7; 7; 7 }{ 8; 8; 8 }{ 9; 9; 9 }Parte 1La primera parte del desafo consiste en encontrar algn nmero uqbariano, sabiendo que ste Es un nmero entero positivo, y Se aparenta con todas las triadas uqbarianasSe deber indicar cul es el nmero uqbariano y dar algn ejemplo de cmo se aparenta con cada triada uqbariana.Parte 2As como existen las triadas, tambin existen los cuartetos, que son conjuntos de cuatro nmeros. Y anlogamente existen los cuartetos uqbarianos que son todos los cuartetos uniformes que van del 1 al 9.Indicar todos los nmeros uqbarianos para los cuartetos.Parte 3Todos estos conjuntos se agrupan dentro de lo que llamamos familias, que se identifican con un rango siendo ste la cantidad de elementos dentro de un conjunto. As, por ejemplo: La familia uqbariana de rango 3 es equivalente a las triadas uqbarianas. La familia uqbariana de rango 4 es equivalente a los cuartetos uqbarianos.Adems, decimos que una familia es compacta cuando se aparenta con todos los nmeros del 1 al 9.Determinar cul es el rango de la primera familia uqbariana compacta.Parte BONUSEste ejercicio fue inspirado en el problema de este video.Para llegar a sus mismos resultados deberamos agregar al programa las operaciones: raz cuadrada y factorial.Ayudas En Prolog las operaciones matemticas son functores! As que podemos relacionarlas como cualquier otro individuo. Por ej: areaCirculo(Radio, pi * Radio ^ 2). % Se relaciona un radio con la FRMULA del rea Se puede hacer la consulta ?- areaCirculo(2, Formula), Area is Formula.Formula = pi*2^2,Area = 12.566370614359172. OJO con Integers vs Floats, porque no son iguales: ?- 0.0 is 1 - 1.false. Tal vez quieras comparar todos los resultados con su representacin flotante: ?- 0.0 is float(1 - 1).true. " + +} , + +{ + +"title" : "Desafios cafe con leche", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/desafios-cafe-con-leche.html", +"date" : "", +"content" : "En muchos cursos de docentes Uqbar se acostumbra dejar desafos caf con leche semanales, que consisten en resolver un problema para el cual hay que comprender a fondo los conceptos vistos en clase, y quizs agregar algo de investigacin extra. Generalmente el docente ofrece un caf con leche como premio al primero que lo resuelve. Aqu se detallan algunos.Haskell Desafo: find con notacin point-free Desafo: Hacer que un data propio sea Enum Desafo: Construir esta sucesin Desafo: Ordenar con arbol B Desafo: sumaParProlog Desafo: Pirmide de nmeros Desafo: Triada UqbarianaSmalltalk Desafo: Suma de distancias" + +} , + +{ + +"title" : "Design temario", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/design-temario.html", +"date" : "", +"content" : "Unidad 1: Diseo y Sistemas Conceptos de Ingeniera de software y de sistemas Diseo y Tecnologa MetamodeloUnidad 2: Diseo y metodologas Introduccin a las metodologas de desarrollo de software El papel del diseo en la metodologa de desarrollo RefactoringUnidad 3: Herramientas de concepcin y comunicacin del diseo ComunicacinUnidad 4: Requerimientos y Diseo Conceptos bsicos del diseo Impacto de los requerimientos en el diseoUnidad 5: Modelado de objetos Cosificacin Diseo y Sistemas de Tipos Manejo de Errores Clase abstracta vs interfaz Clases vs instancias Ciclo de vida de un objeto Template method Double dispatchTecnologasJava Preparacin de un entorno de desarrollo Preparacion de un entorno de desarrollo Java Lambdas en Java 8 Otras tecnologas Preparacion de un entorno de desarrollo Scala Preparacion de un entorno de desarrollo Groovy Preparacion de un entorno de desarrollo Xtend IMPORTANTE: Amigandonos con el entorno de desarrollo Configuraciones generales para cualquier Eclipse Gua de Instalacin de Maven Gua de Instalacin de Ruby Gua de Instalacin de RailsUna pregunta que muchas veces en la materia diseo es: Que lenguaje uso? Ac van algunas comparativas: Groovy vs ScalaUnidad 6: Modelado de datos Normalizacion en ObjetosUnidad 7: Introduccin al diseo de arquitectura Patrones de comunicacin entre componentes Libreria y FrameworkUnidad 8: Validacin del Diseo Validacin del diseo Calidad de las pruebas unitarias CoberturaUnidad 9: Diseo de interfaz de usuarioFuera de progama: Diseo funcional y estructurado Efectos y diseo Evaluacin diferida y diseo Estado, Identidad y diseo Orden superior y diseo Pattern Matching, Polimorfismo y diseo Estereotipos de objetos Tipo abstracto de datosPatrones funcionales en objetos Value Object Function Object Lazy Object y Thunk ObjectTips de C Preparacin del ambiente C Typedefs y tipos annimos Statics Macros Manejo de memoria en C Punteros a funcin Testing en C" + +} , + +{ + +"title" : "Diagrama de clases", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/diagrama-de-clases.html", +"date" : "", +"content" : "El diagrama de clases es una herramienta para comunicar el diseo de un programa orientado a objetos, permitiendo modelar las relaciones entre las entidades. En UML, una clase es representada por un rectngulo que posee tres divisiones: Nombre de la clase, atributos que tiene y mensajes que entiende.En el primer cuadro anotamos el nombre de la clase (si es abstracta se escribe en cursiva, o bien se usa un estereotipo &lt;&gt; arriba del nombre de la clase).En la segunda parte (que para nosotros no ser de tanta importancia) van los atributos (o variables de instancia, las variables de clase van en subrayado).En el ltimo cuadro escribimos las operaciones (qu mensajes que puede entender). No confundir con los mtodos que es cmo lo resuelve cada objeto. Lo importante no es documentar todos los mensajes de un objeto, sino slo los ms relevantes. As quedan fuera los getters, setters, mtodos privados (o auxiliares) y aquellos que uno considere menores. Moraleja: cuidado con las herramientas que en base al cdigo generan el diagrama (y viceversa). Bien vale la pena un diagrama til hecho a mano antes que uno intil en 3D.Importante: Una clase que no tiene comportamiento no est comunicando qu rol cumple en la solucin: o est faltando definir qu le puedo pedir o esa clase no debera estar en el diagrama.Relaciones entre objetosRELACIN USADependencia: uno de los elementos usa o depende del otro cuando: El objeto de clase A recibe o devuelve como parmetro de alguno de sus mtodos un objeto de clase B Si el objeto de clase A instancia un objeto de clase B (pero no lo almacena como variable de instancia, slo vive como variable local en el contexto de un mtodo).Este tipo de relacin indica que los dos elementos colaboran entre s, pero que esa relacin es dbil, casual; tiene un contexto temporal que no trasciende ms all de una operacin. No obstante, sabemos que los cambios en la clase B podran impactar en alguna medida en la clase A.RELACIN CONOCEAsociacin: uno de los elementos conoce al otro, almacenndolo como variable de instancia.Puede definirse una etiqueta que expresa el rol que cumple dicha relacin. En cada extremo de la asociacin puede agregarse la siguiente informacin: un nombre del rol flechas de navegacin: determina el conocimiento (navegabilidad) desde un objeto hacia el otro. multiplicidad: indica cuntos objetos de una clase se relacionan con la otra. La multiplicidad se puede indicar con un rango (0..1, 2..5), un rango sin cota (0..*, 1..*), un valor (1) o una serie de valores (1, 3, 5).En las asociaciones, hay una relacin ms fuerte que en las dependencias (uso) entre ambos elementos. El conocimiento implica que la colaboracin excede el marco temporal de una operacin, aunque cada uno de los objetos sigue teniendo objetivos diferentes.Relaciones entre clasesRELACION HEREDAGeneralizacin: una clase especfica hereda los atributos, relaciones, operaciones y mtodos de otra ms general.Cuando una subclase redefine el comportamiento de su superclase, se escriben los nombres de los mtodos que redefine.RELACIN IMPLEMENTARealizacin: se establece entre una clase y una interfaz; esto implica que la clase debe implementar todas las operaciones que defina la interfaz. Si bien no todos los lenguajes requieren explicitar por cdigo la existencia de una interfaz (en Smalltalk no hace falta, pero en Java s por tener un checkeo de tipos esttico), desde un punto de vista conceptual la interfaz existe y puede comunicarse en el diagrama.Herramientas para diagramaryUML" + +} , + +{ + +"title" : "Diccionarios", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/diccionarios.html", +"date" : "", +"content" : "Un Dictionary es un conjunto de asociaciones entre claves y valores, donde tanto las claves como los valores son objetos cualesquiera.Dicho de otra forma: a un Dictionary puedo pedirle que asocie un objeto valor a un objeto clave. Cada clave puede tener asociado un nico objeto valor en un Dictionary; si asocio un valor a una clave que ya tena otro valor asociado, reemplaza el valor viejo por el nuevo.Para esto se le enva al Dictionary el mensaje at:put: que me diga qu objeto tiene asociado a una clave. Si no tiene ninguno, da error a menos que se lo pida de una forma que evita el error.La forma standard de pedir el valor asociado a una clave es enviarle al Dictionary el mensaje at:; si quiero especificar qu quiero que haga si no encuentra la clave, uso at:ifAbsent: .Un Dictionary es una Collection, entonces los mensajes comunes a todas las Collections se los voy a poder enviar a un Dictionary. Para estos mensajes, se toman slo los valores, p.ej. si pregunto includes: estoy preguntando si contiene un valor, y en select: / collect: / etc. el parmetro va a ser un valor. A pesar de esto, el resultado del select: ser un Dictionary, para los valores para los que el bloque d true va a incluir el par clave/valor correspondiente.Un ejemplo de todo esto: un sencillo diccionario de traduccin de palabras. De esta forma creo un Dictionary y le pongo algunas asociacionesdct:=Dictionarynew.dctat:'uno'put:'one'."Clave'uno',valor'one'"dctat:'dos'put:'two'."Clave'dos',valor'two'"dctat:'tres'put:'three'.dctat:'cuatro'put:'four'.Le pido a dct un elementodctat:'tres'"devuelve'three'"dctat:'cinco'"tiraerror"dctat:'cinco'ifAbsent:['nose']"devuelve'nose'"dctat:'tres'ifAbsent:['nose']"devuelve'three'"Le pido cosas de Collectiondctsize."devuelve4"dctincludes:'dos'"false,trabajasobrelosvalores"dctincludes:'two'"true"dctselect:[:pal|palsize=4]"aDictionary('cuatro'-&gt;'four'),Analizasobrelosvaloresperodevuelveunnuevodiccionariorespetandolasclaves"Ahora, qu pasa si queremos usar las claves, o necesitamos trabajar con los pares clave/valor? Vamos de a poco.Si a un Dictionary le envo el mensaje keys me devuelve un Set con las claves, en caso:dctkeys"devuelveaSet('uno''dos''cuatro''tres')"Este es un nuevo objeto Set, al que le puedo hacer/preguntar lo que quiera, obviamente que si lo modifico el diccionario no se ve afectado. P.ej.dctkeysselect:[:pal|palsize=4]"devuelveaSet('tres')"Ahora veamos cmo trabajar con claves y valores a la vez.Primero me pregunto, si quiero trabajar con los pares clave/valor, es probable que tenga que representar cada par como un objeto. Qu objetos van a ser estos?Respuesta: van a ser instancias de la clase Association. Una Association es un par clave/valor, entiende los mensajes key y value.Si a un Dictionary le envo el mensaje associations, va a devolver una OrderedCollection con sus pares clave/valor representados mediante Associations, p.ej.dctassociations"devuelveanOrderedCollection('uno'-&gt;'one''dos'-&gt;'two''cuatro'-&gt;'four''tres'-&gt;'three')"Entonces, si obtengo uno de estos pares, p.ej.dctassociationsfirstobtengo un objeto al que le puedo pedir key y value. P.ej.dctassociationsfirstkey"respuestaposible:'uno'"dctassociationsfirstvalue"respuestaposible:'one'"Otra vez, esta es una coleccin a la que puedo hacerle cualquier cosa, p.ej.dctassociationsselect:[:assoc|assockeysize=assocvaluesize]"devuelveanOrderedCollection('uno'-&gt;'one''dos'-&gt;'two')"Terminamos con otro ejemplo, una implementacin de un depsito que se acuerda del stock de cada artculo usando un diccionario donde la clave es el artculo y el valor es la cantidad de unidades del artculo en el depsito.#Depsito(v.i.artculos)&gt;&gt;initializeartculos:=Dictionarynew.&gt;&gt;cuantoTensDe:unArtculo^artculosat:unArtculo&gt;&gt;pone:cantde:unArtculoartculosat:unArtculoput:(artculosat:unArtculo)+cant&gt;&gt;saca:cantde:unArtculoartculosat:unArtculoput:(artculosat:unArtculo)-cant&gt;&gt;cantidadTotalDeUnidades"trabajasobrelosvalores,quesonlascantidades"^artculosinject:0into:[:x:elem|x+elem].&gt;&gt;valorTotalDeposito"aassockey(elartculo)lepidoelprecio,assocvalueeslacantidaddeeseartculoeneldepsito"^artculosassociationsinject:0into:[:x:assoc|x+assockeyprecio*assocvalue].Algo importante a tener en cuenta al usar un diccionario es detenerse a pensar si no nos est faltando una abstraccin que deberamos modelar en vez de manejar asociaciones de valores. A una asociacin no le podemos agregar comportamiento, con lo cual la lgica que trabaja con los valores asociados est en el objeto que tiene el mapa (como en este caso se puede ver en el producto entre el precio y la cantidad en el depsito), esa asociacin bien podra reemplazarse por un objeto propio que conozca al producto y la cantidad que hay en stock al cual s podramos agregarle comportamiento. Forma parte de disear la solucin decidir si es buena idea o no usar un diccionario en vez de una coleccin con objetos de dominio que, adems de asociar otros objetos, tengan responsabilidades propias." + +} , + +{ + +"title" : "Diferencia entre objetos y procedural con un ejercicio de la guia 1", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/diferencia-entre-objetos-y-procedural---con-un-ejercicio-de-la-guia-1.html", +"date" : "", +"content" : "Veamos el ejercicio de la gua 1 que habla del sueldo de Pepe. El sueldo de Pepe es su sueldo bsico ms su bono por presentismo ms otras cosas. De bono hay dos tipos uno que es: 100 pesos si no falt nunca, 50 pesos si falt un da, 0 si falt dos o ms das. otro que es siempre 0Podran imaginarse ms bonos: uno que es 200 si faltaste hasta 2 veces y 0 si faltaste 3 o ms, otro que es lo mismo pero el doble en diciembre, uno que va subiendo 10 pesos cada vez que se paga en meses consecutivos (100 el primer mes, 110 el segundo, etc., as te tents a no faltar nunca). El ejercicio plantea dos variantes de bono x presentismo para que no se haga tan largo resolverlo, est bueno pensar que puede haber ms.Si Pepe puede tener varias variantes de bono por presentismo, no es nada lindo que el cdigo sea algo ascalculaPresentismo: diasQueFalto(bonoPorPresentismo=1)"elquedependedecuntosdasfalt"ifTrue:[(diasQueFalto=0)ifTrue:[^100].(diasQueFalto=1)ifTrue:[^50].^0].(bonoPorPresentismo=2)"siempre0"ifTrue:[^0].(bonoPorPresentismo=3)"otroqueaparezcadespus"ifTrue:[...loquecorrespondaenestecaso].la salida en este caso es darse cuenta que conviene modelar el bono por presentismo como un objeto distinto de pepe, y que pepe tenga una variable a su bono por presentismo. Se lo setes desde el workspace. Entonces el que calcula el valor es el bono, para lo cual necesita saber los das que falt, entonces pepe le pregunta a su bono as:bonoPresentismoimporteSegun:diasFaltadosdonde bonoPresentismo y diasFaltados son variables de pepe.Fjense que los bonos son todos polimrficos para Pepe.Posta es altsimamente importante que vean esto, es la papota bsica de objetos: poder representar cada ente que tiene comportamiento propio (en este caso el bono x presentismo) como un objeto, y si tiene varias variantes que se comportan distinto, hacer varios objetos que sean polimrficos entre s para los otros objetos que tengan que usar ese comportamiento. Si se entiende bien, muchas cosas (en PDP, en Diseo y despus en el laburo) se simplifican." + +} , + +{ + +"title" : "Diferencias entre polimorfismo abstraccion y encapsulamiento", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/diferencias-entre-polimorfismo--abstraccion-y-encapsulamiento.html", +"date" : "", +"content" : "La discusin se dispara por una consulta sobre el ejercicio 2a de este final de 2009.Un alumno propone los siguientes cambios, los cuales son vlidos para lo que se plantea en el ejercicio: Que la variable de instancia tipo referencie a un objeto que puede ser de las clases MateriaPrima, ProductoSemiElaborado y ProductoTerminado, y estas clases sean clases independientes, es decir que no sean subclases de ninguna ya que segn el diagrama no comparten caractersticas. Entonces ahora Material deja de ser clase abstracta, para crear un material creamos un objeto de la clase Material, y a la variable tipo le asignamos un objeto de la clase de material que corresponda (MateriaPrima, ProductoSemiElaborado o ProductoTerminado).De la mano de esta justificacin conceptual: Aprovechariamos el concepto de polimorfismo y el de abstraccin, ya que para la clase sector es transparente este cambio (abstraccin), ella le va pedir el costoAlmacenamiento() a su lista de materiales y despues cada material le va a pedir a su tipo el costoAlmacenamiento(), aca se aplica el polimorfismo ya que no importa el tipo del material que sea el objeto material, todos los tipos van a entender el mensaje costoAlmacenamiento(). Y aparte esta solucin permite que el dia de maana si se quiere agregar un nuevo tipo de material solo hay que crear la clase de ese nuevo tipo y que en sus metodos de instancia este el mtodo costoAlmacenamiento() y listo, ya se la puede referenciar con la variable de instancia tipo. Esto es una caracteristica tmb no? pero no me acuerdo como se llama.A continuacin mostramos la explicacin por parte del docente: El nico detalle que yo marcara es con respecto a los conceptos que vos mencions. Yo creo por la forma en que uss la palabra abstraccin, lo que ests queriendo decir es encapsulamiento. Tal vez es sutil la diferencia, porque se puede ver al encapsulamiento como una forma de abstraccin; pero quedara mejor tu respuesta si hacs el cambio que yo te digo. O sea cuando vos decs para la clase sector es transparente este cambio, eso es encapsulamiento (que los clientes de un objeto no tengan que saber de su implementacin interna) o desacoplamiento (que el cambio a una parte de un sistema no afecte a las otras) La clave est en la palabra transparente; La abstraccin ira por el lado de encontrar una idea o un concepto que capture la esencia de (una parte de) mi problema y a partir de ah me permita guiar el diseo. La abstraccin en este caso podra ser el tipo de material, las tres clases que vos hacs polimrficas (MateriaPrima, ProductoSemielaborado, ProductoTerminado) en tu solucin intentan ser tres versiones de un mismo concepto que no estaba en la solucin inicial. Encontrar ese concepto es abstraer o encontrar una abstraccin. Pasaste de ideas concretas (MateriaPrima, etc) a una idea ms abstracta (tipo de material) que permite pensar a los otros como variantes de una misma cosa. El encontrar esa abstraccin es lo que te permite luego pensar en hacer a los participantes de esa abstraccin polimrficos entre s." + +} , + +{ + +"title" : "Diseno iterativo", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/diseno-iterativo.html", +"date" : "", +"content" : "La metodologa de desarrollo nos lleva a disear de dos formas completamente diferentes:Las metodologas predictivas proponen el diseo anticipado, donde se asume que el anlisis ya ha relevado todos los procesos que el usuario necesita tenemos disponible toda la informacin para poder definir cada proceso no habr cambios en los requerimientos hasta nuestra implementacin el usuario no har cambios o nuevos pedidos. no habr cambios externos al sistema que obliguen a modificarlo (como disposiciones legales). si el diseo es adecuado, la codificacin se ajustar perfectamente a lo que el usuario necesita. para ello hay que documentar el sistema en su completitud para que los programadores no tengan que tomar decisiones de diseo en la codificacin. en la fase de diseo no se debe programar, dado que se estara solapando la actividad (de la misma manera que en la fase de codificacin no se debe disear)Esta forma de disear tambin se conoce como Big Design Up Front. En este artculo el autor expone algunos argumentos en favor de esta metodologa.Por el contrario, las metodologas adaptativas proponen el diseo iterativo, donde se asume que slo tenemos algunos procesos relevados, y aunque los tuviramos en su totalidad, los requerimientos podran cambiar. es inocente pensar en que no habr cambios en los requerimientos, dado que el usuario no sabe exactamente lo que se va a construir y tiene derecho a pedir modificaciones cuando se da cuenta de que cometi un error al dar informacin al diseador. bajo la premisa anterior el diseador no puede realizar un diseo que no est sujeto a cambios, por los errores propios que adems podra cometer. si el diseo no es adecuado, debemos cambiarlo lo ms pronto posible. Esto incluye la fase de codificacin. si queremos reflejar la realidad, tenemos que permitir que haya alternancia entre diseo y programacin. No paralelizamos las actividades, sino que una se va solapando a la otra, como en una pila. el diseo iterativo considera que los errores son parte del desarrollo mismo y necesitamos poder modificar el diseo en cualquier momento, sin que eso paralice el proyecto (iterativo tiene mucho de prueba y error). simplest thing that could possible work En este artculo Martin Fowler explica el diseo desde el punto de vista de las metodologas giles.El costo del cambioTradicionalmente las metodologas secuenciales interpretan que le costo de corregir un error o de introducir un cambio en un desarrollo de software se incrementa exponencialmente a medida que se avanza con el desarrollo. Segn esta visin, un error en el anlisis que podra corregirse en un par de horas de trabajo, tardar das en solucionarse si se lo detecta durante la etapa de diseo e incluso podra requerir de varias semanas si se lo encuentra recin durante la etapa de construccin.Varios autores, entre ellos Kent Beck han propuesto otra interpretacin. Segn esta nueva perspectiva la curva del cambio es radicalmente distinta para los proyectos de software en la actualidad. La valoracin incorrecta del costo del cambio proviene en parte por la asociacin con otras ingenieras; en las ingenieras que trabajan con entidades fsicas hacer una modificacin sobre algo construido suele ser muy costoso, incluso en algunos casos imposible. Esto no es vlido para una ingeniera que trabaja con productos tan abstractos y maleables como el software. Adicionalmente la ingeniera del software se diferencia radicalmente de las otras en cuanto a que el costo de reproduccin de un producto una vez construido es insignificante (comprese el costo de construir una nueva unidad de un automvil determinado en una lnea de produccin con el costo de producir una nueva unidad de un programa que se vende en forma masiva).Por otro lado, las herramientas para el desarrollo de software han evolucionado notablemente en los ltimos aos, apareciendo entornos integrados de desarrollo, lenguajes de muy alto nivel, herramientas de versionado, refactorings automticos, herramientas de integracin contnua, entre otros. A modo de ejemplo, podemos considerar el costo de cambiar el nombre de una variable en un entorno de desarrollo que no tenga la capacidad de hacerlo automticamente en un programa grande con la simplicidad de hacerlo en un entorno de los que se usan hoy en da. El tiempo se reduce apenas a segundos.Segn la interpretacin de Beck, cualquier cambio es realizable con un costo relativamente bajo aun en etapas avanzadas del desarrollo. Otros autores sugieren que hay algunos cambios para los cuales se puede aplanar la curva del costo y otros cambios para los que no. Por ejemplo, se ha sugerido que los errores arquitecturales tienden a tener curvas empinadas. Si bien es imaginable que en la medida que las herramientas (tanto tecnolgicas como conceptuales) evolucionen, ms y ms decisiones puedan tomarse considerando la posibilidad de modidicarlas mas adelante sin que esto implique un costo alto, todava hoy en da es importante detectar para cada decisin que tomamos en una etapa temprana del desarrollo si el costo potencial de un error es elevado o no." + +} , + +{ + +"title" : "Diseno y sistemas de tipos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/diseno-y-sistemas-de-tipos.html", +"date" : "", +"content" : "En programacin el chequeo esttico de tipos permite detectar errores en un programa de forma previa a su ejecucin. Existen amantes y detractores de esta idea y existen lenguajes profesionales con y sin chequeo de tipos. Quienes apoyan el uso de estos mecanismos sostienen que este tipo de chequeos garantiza o ayuda a garantizar la ausencia de errores en los programas, mientras que los que prefieren evitar estos chequeos sostienen que: a menudo resultan limitantes descartando soluciones que podran ser viables que agregar la informacin de tipos a un programa es trabajoso y reduce su legibilidad y finalmente que las garantas que otorga un sistema de tipos pueden lograrse por otros mecanismos (como el testeo unitario).Cmo afecta el chequeo de tipos a la actividad de diseo? Si para disear utilizamos herramientas capaces de validarlos, entonces podran ayudar a detectar errores. De estas herramientas podemos ver dos sabores: Herramientas que permiten construir diagramas y realizan chequeos sobre esos diagramas. Si utilizamos cdigo, o pseudo-cdigo como herramientas dentro del proceso de diseo, podemos utilizar los chequeos de tipos en esos programas para detectar problemas. Esto puede resultar particularmente importante al realizar rediseos y pruebas de rediseo sobre un programa ya construido. El sistema de tipos de la tecnologa en la que se construye el programa diseado establece restricciones sobre lo que se puede programar en ese lenguaje; entonces, si al disear no tengo en cuenta esas restricciones corro el riesgo de producir un diseo que luego no es fcil (o incluso no es posible) de construir en la tecnologa elegida. El sistema de tipos forma parte del metamodelo del lenguaje de programacin; uno puede elegir establecer una relacin ms o menos cercana entre ambos metamodelos, con las consecuencias ya explicadas. Finalmente, un tipo determina el conjunto de operaciones que se puede realizar sobre una entidad (entre otras cosas). Por entidad podemos entender cualquier porcin de un sistema: objeto, clase, procedimiento, subsistema, tipo abstracto de datos, etc. Es posible establecer una relacin directa entre las operaciones y las responsabilidades e interfaces asociadas a una parte de un sistema (que son objetivos especficos del diseo). Definir tipos es una forma de definir las interfaces entre entidades de software. Adicionalmente en sistemas de tipos con presencia de polimorfismo, un tipo no define la interfaz de una entidad sino que define un contrato que podran cumplir mltiples entidades distintas." + +} , + +{ + +"title" : "Diseno y tecnologia", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/diseno-y-tecnologia.html", +"date" : "", +"content" : "Existe una fuerte relacin entre diseo y la programacin, o mejor dicho, entre el diseo y la tecnologa que voy a utilizar para construir el sistema.El nivel de detalle del diseoEn primer lugar podemos analizar el nivel de detalle de ambos. Obviamente el programa tendr muchos detalles ms que el diseo, necesita poder ser compilado y ejecutado, incluir todos esos detalles en la especificacin de diseo sera contraproducente porque nos obligamos a decidir sobre cada uno de esos puntos y tal vez convenga postergar algunas decisiones para el momento de programar. En el extremo, si el diseo definiera todos los detalles del programa subyacente, entonces la programacin posterior no requiere de tomar ninguna decisin y por lo tanto podra automatizarse. En ese caso la programacin deja de tener sentido como actividad, la puedo considerar un paso ms de la compilacin y nuestro diseo podra considerarse directamente como un programa.A medida que los lenguajes de programacin fueron siendo cada vez de ms alto nivel y fueron incorporando mejores abstracciones (podemos destacar el manejo automtico de memoria como un ejemplo esencial), la diferencia entre el nivel de abstraccin del diseo y del programa se fue achicando. En la literatura podemos encontrar dos visiones de este proceso. Algunas metodologas como MDA consideran que slo debemos disear y debemos descartar la programacin como actividad. Entonces la ingeniera de software debera dedicarse a producir modelos, y los programas deberan derivarse automticamente de esos modelos. Otras metodologas como XP incorporan el diseo como parte de la actividad, y entonces consideran que la nica actividad es la programacin. Como referencia de este pensamiento puede leerse el artculo de Martin Fowler: Is Design Dead?Ambas visiones no son tan distintas entre s, en definitiva el diseo y el programa se acercan, y finalmente la nica discusin restante es si nuestros modelos/programas debern tener forma de diagrama o si tendrn forma de texto. (Y si se combinan ambos? Hay otras posibilidades? todas son preguntas para las que hoy la ciencia del desarrollo de software no tiene respuestas nicas)Por otro lado, un diseo de muy alto nivel deja muchos detalles a responsabilidad de la persona que va a construir. Si el modelo deja abiertas cuestiones que tienen que ver (por ejemplo) con la forma en que se estructurar el programa entonces est postergando decisiones que son de diseo aunque las tome una persona cuyo rol formal es el de programador. En ese caso lo que pasa es que el programador es el que est llevando a cabo el nivel ms detallado del diseo. Esto no tiene por qu ser algo negativo, es una forma de organizacin perfectamente vlida, en la cual algunas personas toman la responsabilidad del diseo a alto nivel (podra llamarse incluso arquitectura) y a otras les toca ocuparse del diseo ms detallado.Metamodelos en el diseo y metamodelos en el programaLa otra perspectiva desde la que podramos analizar la relacin entre diseo y tecnologa es pensar la relacin entre el metamodelo que usamos para disear y el metamodelo del lenguaje que usaremos para construir.Si esos metamodelos coinciden entonces lo que yo disee puede que sea ms fcil de construir (o de visualizar la relacin entre lo construido y el modelo). Pero, de nuevo, un metamodelo para un programa puede requerir de muchos detalles que en determinado momento del diseo todava no estoy en condiciones de decidir. Un ejemplo comn es tener que decidir si queremos poner una clase abstracta o una interfaz cuando todava no hemos definido los detalles del concepto asociado.Entonces dependiendo del nivel de detalle de nuestro diseo tal vez convenga elegir metamodelos ms o menos parecidos a los metamodelos de nuestra tecnologa subyacente: Utilizar metamodelos sutilmente diferentes nos permite disear con ms libertad, desprendindonos de complejidades y restricciones tecnolgicas. Pero las diferencias entre ambos metamodelos plantean gaps que luego habr que resolver al construir, entonces no podemos permitir que ambos metamodelos tengan diferencias demasiado fundamentales.En resumen, el diseo es la especificacin de lo que quiero construir. Entonces, al elegir la forma en la que quiero disear, las herramientas que uso para disear tengo que entender la relacin que establezco con la tecnologa usada para la construccin. Si las dos ideas se parecen mucho eso puede plantear restricciones muy tempranamente, si planteo actividades distintas es porque quiero ponerles focos distintos, usar herramientas distintas. Pero si las dos ideas van por caminos muy distintos entonces puede que el diseo pierda utilidad, porque para poder construir voy a tener que llenar los huecos (gaps) que el modelo de diseo no cubra. En definitiva, no es posible construir sin llenar esos huecos, y llenar esos huecos es disear." + +} , + +{ + +"title" : "Paradigma logico, Predicado distinct", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/distinct.html", +"date" : "", +"content" : "MotivacinQu pasa cuando un predicado encuentra la misma respuesta por varios caminos?Si tens:?- esPicaro(Quien).Quien=pepe,Quien=pepe,Quien=juan,Quien=pepe,Quien=juan.Esto est bien! No importa por cuntos caminos llegue a la misma persona, lo que importa es que cuando unifique unifique con los que son pcaros.El problema es cuando quers encontrar cuntos pcaros son, es decir, cuando quers agregar los datos. Por ejemplo haras:findall(Picaro,esPicaro(Picaro),Picaros),length(Picaros,CuantosPicaros).Y quers que te d 2 (pepe y juan), no 5.Bueno, en ese caso, pods utilizar el predicado de orden superior distinct/2, de esta forma:?- distinct(Quien,esPicaro(Quien)).Quien=pepe,Quien=juan.Y entonces te queda as:findall(Picaro,distinct(Picaro,esPicaro(Picaro)),Picaros),length(Picaros,CuantosPicaros)." + +} , + +{ + +"title" : "Dont Cross the Beams by Kent Beck", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/dont-cross-the-beams.html", +"date" : "", +"content" : "OrigenActualmente threeriversinstituteorg no esta activo, tome el articulo de Kent Beck de archives.org en este [link](http://web.archive.org/web/20130113095840/http://www.threeriversinstitute.org/blog/?p=594)ArticuloIntroAs many of my pair programming partners could tell you, I have the annoying habit of saying Stop thinking during refactoring. Ive always known this isnt exactly what I meant, because I cant mean it literally, but Ive never had a better explanation of what I meant until now. So, apologies yall, heres what I wished I had said.One of the challenges of refactoring is successionhow to slice the work of a refactoring into safe steps and how to order those steps. The two factors complicating succession in refactoring are efficiency and uncertainty. Working in safe steps its imperative to take those steps as quickly as possible to achieve overall efficiency. At the same time, refactorings are frequently uncertainI think I can move this field over there, but Im not sureand going down a dead-end at high speed is not actually efficient.Inexperienced responsive designers can get in a state where they try to move quickly on refactorings that are unlikely to work out, get burned, then move slowly and cautiously on refactorings that are sure to pay off. Sometimes they will make real progress, but go try a risky refactoring before reaching a stable-but-incomplete state. Thinking of refactorings as horizontal and vertical is a heuristic for turning this situation aroundeliminating risk quickly and exploiting proven opportunities efficiently.The other day I was in the middle of a big refactoring when I recognized the difference between horizontal and vertical refactorings and realized that the code we were working on would make a good example (good examples are by far the hardest part of explaining design). The code in question selected a subset of menu items for inclusion in a user interface. The original code was ten if statements in a row. Some of the conditions were similar, but none were identical. Our first step was to extract 10 Choice objects, each of which had an isValid method and a widget method.before:if (...choice 1 valid...) { add($widget1);}if (...choice 2 valid...) { add($widget2);}... after:$choices = array(new Choice1(), new Choice2(), ...);foreach ($choices as $each) if ($each-&gt;isValid()) add($each-&gt;widget());After we had done this, we noticed that the isValid methods had feature envy. Each of them extracted data from an A and a B and used that data to determine whether the choice would be added.Choice1 isValid() { $data1 = $this-&gt;a-&gt;data1; $data2 = $this-&gt;a-&gt;data2; $data3 = $this-&gt;a-&gt;b-&gt;data3; $data4 = $this-&gt;a-&gt;b-&gt;data4; return ...some expression of data1-4...;}We wanted to move the logic to the data.Choice1 isValid() { return $this-&gt;a-&gt;isChoice1Valid();}A isChoice1Valid() { return ...some expression of data1-2 &amp;&amp; $this-b-&gt;isChoice1Valid();}SuccessionWhich Choice should we work on first? Should we move logic to A first and then B, or B first and then A? How much do we work on one Choice before moving to the next? What about other refactoring opportunities we see as we go along? These are the kinds of succession questions that make refactoring an art.Since we only suspected that it would be possible to move the isValid methods to A, it didnt matter much which Choice we started with. The first question to answer was, Can we move logic to A? We picked Choice. The refactoring worked, so we had code that looked like:A isChoice1Valid() { $data3 = $this-&gt;b-&gt;data3; $data4 = $this-&gt;b-&gt;data4; return ...some expression of data1-4...;}Again we had a succession decision. Do we move part of the logic along to B or do we go on to the next Choice? I pushed for a change of direction, to go on to the next Choice. I had a couple of reasons: The code was already clearly cleaner and I wanted to realize that value if possible by refactoring all of the Choices. One of the other Choices might still be a problem, and the further we went with our current line of refactoring, the more time we would waste if we hit a dead end and had to backtrack.The first refactoring (move a method to A) is a vertical refactoring. I think of it as moving a method or field up or down the call stack, hence the vertical tag. The phase of refactoring where we repeat our success with a bunch of siblings is horizontal, by contrast, because there is no clear ordering between, in our case, the different Choices.Because we knew that moving the method into A could work, while we were refactoring the other Choices we paid attention to optimization. We tried to come up with creative ways to accomplish the same refactoring safely, but with fewer steps by composing various smaller refactorings in different ways. By putting our heads down and getting through the other nine Choices, we got them done quickly and validated that none of them contained hidden complexities that would invalidate our plan.Doing the same thing ten times in a row is boring. Half way through my partner started getting good ideas about how to move some of the functionality to B. Thats when I told him to stop thinking. I dont actually want him to stop thinking, I just wanted him to stay focused on what we were doing. Theres no sense pounding a piton in half way then stopping because you see where you want to pound the next one in.As it turned out, by the time we were done moving logic to A, we were tired enough that resting was our most productive activity. However, we had code in a consistent state (all the implementations of isValid simply delegated to A) and we knew exactly what we wanted to do next.ConclusionNot all refactorings require horizontal phases. If you have one big ugly method, you create a Method Object for it, and break the method into tidy shiny pieces, you may be working vertically the whole time. However, when you have multiple callers to refactor or multiple implementors to refactor, its time to begin paying attention to going back and forth between vertical and horizontal, keeping the two separate, and staying aware of how deep to push the vertical refactorings.Keeping an index card next to my computer helps me stay focused. When I see the opportunity for a vertical refactoring in the midst of a horizontal phase (or vice versa) I jot the idea down on the card and get back to what I was doing. This allows me to efficiently finish one job before moving onto the next, while at the same time not losing any good ideas. At its best, this process feels like meditation, where you stay aware of your breath and dont get caught in the spiral of your own thoughts." + +} , + +{ + +"title" : "Double dispatch", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/double-dispatch.html", +"date" : "", +"content" : "Double dispatch es un patrn de diseo que permite de tomar una decision a partir de varios objetos en vez de uno solo.En las implementaciones de lenguajes de objetos mainstream, la decisin de qu mtodo se va a ejecutar se hace a partir del objeto receptor del mensaje.Sin embargo, a veces con el objeto receptor no alcanza.Para dar un ejemplo trivial pero ilustrativo, en el juego de piedra, papel, tijera, la decision de quien gana y quien pierde depende de dos objetos y no de uno solo.En dicho caso, una solucin posible es que uno de los dos objetos delegue la decisin al segundo, dndole informacin de s mismo. En este caso, el primer objeto va a avisarle al segundo objeto quin es (en este caso una piedra), y el segundo objeto va a decidir quien gana sabiendo eso: otra piedra va a decidir empate, una tijera que gana la piedra, y un papel que gana el papel.Piedra &gt;&gt; quienGanaContra: otro ^ otro quienGanaContraPiedra: selfPiedra &gt;&gt; quienGanaContraPiedra: unaPiedra ^ nil Papel &gt;&gt; quienGanaContraPiedra: unaPiedra ^ self Tijera &gt;&gt; quienGanaContraPiedra: unaPiedra ^ unaPiedra...Una definicin posible de Double Dispatch, es la propuesta por Ralph Johnson.Qu criterio de dispatch utilizar?Johnson entiende que el Double Dispatch siempre va a sociado a la clase del segundo objeto; si bien comprende eso como un Code Smell lo asume inevitable y caracterstico del Double Dispatch.Sin embargo, otra forma de interpretarlo sera que el mejor Double Dispatch es el que logra evitar el code smell y en lugar de realizar el dispatch sobre el tipo del parmetro lo hace en funcin al rol que ocupa, es decir, dndole significado ms all del tipo en s. Por supuesto este tipo de double dispatch requiere de un diseo un poco ms, pero es esperable que sea ms extensible: si el dispatch se realiza por el tipo tenemos dos desventajas claras: Explosin combinatoria (como explica Johnson si tenemos 6 subtipos diferentes podemos tener 6x6 combinaciones de dispatchs). No extensible, ya que agregar un nuevo tipo implicara necesariamente agregar todas las combinaciones posibles.Esto no descarta la posibilidad de realizar un double dispatch basado en tipos, pero considera que el code smell no puede ser ignorado y por lo se prefiere evitar esa forma de utilizacin. En una estrategia de dispatch basada en el comportamiento de los objetos, es ms probable que los nuevos casos que surjan puedan asociarse a alguno de los roles preexistentes.Qu usos tiene?Unos de los usos principales del double dispatch son los patrones de diseo de objetos visitor e interpreter.El patrn visitor sirve para hacer extensible una estructura de datos, modelando operaciones sobre la estructura como objetos visitantes.Los usuarios pueden definir nuevos visitantes, y cada visitante sabe como tiene que manipular cada objeto en la estructura de datos usando el double dispatch.Otro posible uso es para implementar el patron interpreter, un patron usado para evaluar sentencias de un programa.En el patron interpreter, un programa se representa como un rbol, sobre el que uno puede implementar el patron visitor, donde un objeto intrprete juegue el rol de visitante." + +} , + +{ + +"title" : "Dsl", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/dsl.html", +"date" : "", +"content" : "DSL viene de las siglas en ingls Domain-Specific Language.Un DSL es un lenguaje ideado para expresar cierta parte de un sistema. Por eso se dice que es un lenguaje de propsito especfico, a diferencia de los lenguajes de propsito general (GPL).Los lenguajes con los que estamos acostumbrados a trabajar, como Java, Haskell o Groovy tienen la caracterstica de que pueden ser utilizados para resolver problemas de programacin de cualquier ndole, por lo que decimos que son lenguajes de propsito general (GPL por sus siglas en ingls).Estos lenguajes son Turing-complete, siendo capaces de expresar cualquier algoritmo, y pudiendo ser aplicados a cualquier dominio. Con estos lenguajes, con mayor o menor facilidad o eficiencia, podemos construir sistemas de clculo impositivo, implementar algoritmos de aprendizaje de mquina, etc. Es decir, son lenguajes que pretenden ser igualmente efectivos (igualmente buenos o malos) en todos los campos de accion.Sin embargo, el empleo GPLs para expresar problemas muy especficos, si bien es posible, puede significar mayor esfuerzo de lo que uno deseara, dado que las abstracciones que estos dominios plantean no estn soportadas nativamente por el lenguaje; no son primitivas. Por ejemplo, escribir una transposicin de matrices, an contando con API bien diseada, es ciertamente ms complejo en Java que en Mathematica u Octave, y lenguajes como SQL estn especficamente diseados para realizar operaciones sobre una base datos.Estos lenguajes son especficos de un dominio particular (DSL, domain-specific languages), y si bien no pueden resolver todos los problemas, resuelven aquellos para los que fueron diseados mejor que los GPL.Qu quiere decir esto ? propsito general propsito especfico Abarca construir la totalidad de la aplicacin una parte de la aplicacin Tipo de Aplicacn cualquiera un solo tipo Conceptos generales: - funcin (en funcional), - clase, objeto, mtodo (en OOP), - variable, predicado (en lgico)... | del (nico) dominio | | Ejemplos | C, Java, Smalltalk, Self, ADA, Haskell, Prolog... | [xpath](http://es.wikipedia.org/wiki/XPath), SQL, [pic](http://macroexpand.org/doku.php?id=articles:uml-sequence-diagram-dsl-txl:start), [sed](http://es.wikipedia.org/wiki/Sed_(inform%C3%A1tica))... |Problema que ataca un DSLEn general cuando nos enfrentamos a un problema de programacin aparecen varias actividades que trataremos de simplificar ampliamente ac: Entendimiento del problema/dominio Formacin conceptual de una solucin Implementacin en un lenguaje de programacin Compilacin, ejecucin y pruebas.Normalmente trabajamos con un nico paradigma de programacin y unos pocos lenguajes. Estos lenguajes permiten expresar sobre ellos cualquier tipo de dominio, es decir que se utilizan para desarrollar cualquier tipo de aplicacin. Por esto es que se llaman lenguajes de propsito general (GPL del ingls).En el proceso de entendimiento del dominio podramos trabajar completamente abstractos del lenguaje de programacin, simplemente tratando de relevar informacin y requerimientos. No vamos a entrar en detalles ac acerca de esta etapa, pero lo que nos interesa es que se podra hacer una anlisis del problema independiente del lenguaje de programacin y hasta del paradigma.Durante la formacin conceptual de una solucin ya debemos pensar el dominio dentro de uno o varios paradigmas (en caso en que osemos desarrollar la solucin con mltiples paradigmas), de acuerdo a nuestra experiencia, o lo que veamos que mejor se adapte a la problemtica.Por ejemplo, hay problemas que son inherentemente ms fciles de implementar en el paradigma lgico que en objetos, o funcional, etc. Sin embargo, todava podramos pensar en una solucin independiente del lenguaje.Por ejemplo, en objetos es donde identificamos: objetos y clases. responsabilidades (mensajes). interacciones y colaboraciones. jerarquas / traits (lgica comn y reutilizacin. etc.Luego tenemos que realmente implementar esta solucin abstracta en los pasos 3 y 4, y para eso utilizamos un GPL.Y ac va el problema: El mapeo de la solucin conceptual con el lenguaje no es directo, no suele ser trivial. A veces no tenemos soporte del lenguaje para ciertas abstracciones de nuestro dominio: Los ejemplos ms simples son los patrones como singleton, delegacin automtica, etc. Estamos forzados a adaptar el dominio y nuestra solucin al lenguaje.Y eso es lo que hacemos siempre, adaptamos al lenguaje que tenemos a mano. Eso nos lleva a que nuestra solucin va a estar siempre de aqu en adelante expresada en un lenguaje que no es el ms cercano al problema/dominio, sino ms bien a un lenguaje de programacin general.Algunas consecuencias:Legibilidad: Nuestro cdigo contendr una mezcla entre conceptos de dominio (una Cuenta, un Cliente, etc) y palabras propias del lenguajes (keywords, como public class, trait, etc). Quien se incorpore al proyecto o quiera revisar la solucin deber, naturalmente, hacer el proceso inverso, como una ingeniera reversa, a partir del cdigo y de lo expresado en el GPL abstraerse para generar una representacin mental del problema/dominio.Flexibilidad (cambios de requerimientos o dominio): Naturalmente solo podrn ser implementados por desarrolladores que entiendan no solo el dominio, sino adems el GPL. Cada nuevo cambio deber ser traducido nuevamente de dominio hacia GPL.Duplicacin: Tendremos al menos dos representaciones de la solucin, la mental (que muchas veces adems se plasma en documentos de especificacin y anlisis) y la traduccin/implementacin en el GPL.Estas consecuencias hacen que la programacin dedique la mayor parte del tiempo y esfuerzo en lidiar con los problemas de traduccin e implementacin de la solucin al GPL.Entonces, una va alternativa sera en pensar que en lugar de adaptar nuestra solucin a un lenguaje, podemos adaptar el lenguaje a nuestra solucin.A esto se lo conoce como Language-Oriented Programming, desde el punto de vista de un nuevo paradigma. Y una de las prcticas es crear un nuevo lenguaje para expresar nuestra solucin o una parte de la solucin. Esto es un DSL.Motivacin para hacer un DSLSuponemos que con la comparacin que ya vimos, aparecen varias razones. Pero vamos a enumerarlas ac para resumir: para acercar la brecha entre la descripcin del problema en trminos abstractos (descripcin del dominio) y la implementacin de la computacin que lo resuelve / ejecuta. Facilitara la comunicacin con gente no-tcnica. No programadores podran entenderlo y escribirlo. para esconder los detalles internos de la lgica comn o las construcciones propias del lenguaje para configuraciones de ciertas partes de la aplicacin. para expresar de forma declarativa ciertas reglas del negocio, que se va a separar de la forma en que se interprete y ejecute esa regla. Ej: regular expressions. para la creacin de un grafo complejo de objetos, problema que normalmente solucionamos con patrones creacionales, como factories, builders &amp; prototypes.Cuando necesito un DSL? Como aproximacin, diremos que si la cantidad de problemas en este domino especfico que queremos resolver es pequeo, o la complejidad de crear el DSL es mayor que la resolver el problema en nuestro GPL, probablemente no lo necesitemos. De lo contrario, ser una alternativa a considerar.Tipos de DSLsA grandes rasgos, podramos catalogar los DSLs a travs de las siguientes categoras. Existen autores que refinan mucho ms a detalle la categorizacin, incluyendo nuevos tipos. A fines prcticos de explicar la idea general a nivel de programacin, nosotros optamos por acotar esa categorizacin: Parser + Compilador Interprete Compilador: traduce a lenguaje maquina ejecutable: puede ser assembler o un lenguaje ejecutable por una VM como java, etc. Interprete: a medida que se va parseando (leyendo) el cdigo de expresado en el DSL, se va ejecutando, sin haber generado cdigo ejecutable como paso intermedio. Traductor: son los famosos generadores de cdigo. si bien se podra trazar una analoga con los compiladores, ya que tambin generan cdigo, la diferencia es que los traductores generan cdigo que no es ejecutable de por s, sino ms bien cdigo de otro lenguaje. Ejemplo: generadores de cdigo. a travs de Java APT (annotation processing tool) Embebidos: se utiliza un lenguaje GPL, pero se lo usa de tal manera de simular o asemejarse lo mayor posible a un lenguaje propio del dominio con syntax sugar y un diseo de APIs especial, llamado Fluent Interfaces, se acerca de un lenguaje de dominio. aprovechar las caractersticas del lenguaje GPL existente, Evita tener que hacer un parser, compilador e interprete. Ej: ruby DSL InternoDesarrollados como un API dentro de un lenguaje de proposito general, que se ejecutan en su mismo ambiente, llamado lenguaje husped.Si comparamos los DSLs internos y externos, en general los segundos sern mas flexibles, pero tambin el esfuerzo de implementarlos ser mayor, no slo porque la complejidad de implementar un parser a mano es mayor, sino que probablemente el lenguaje husped nos proveer muchas construcciones y bibliotecas tiles. (Digresin: aprovechar las bibliotecas existentes para otro lenguaje es un punto muy importante tambin a la hora de disear un GPL. As es como surge gran cantidad de lenguajes que corren sobre la mquina virtual de Java o .Net)Ejemplo de DSL interno para definir especificaciones aprovechando features de lenguajes dinmicosDSL ExternoDesarrollados como un lenguaje independiente, compilado, interpretado o una mezcla de ambos, que se ejecuta en un ambiente independiente, y no guarda necesariamente relacin con el lenguaje en que est escrito el parser.Ventajas Libertad absoluta sobre la sintaxis del lenguaje (solo limitada por capacidad de implementacin del parser, etc), por eso.. Mayor expresividad del dominio.Desventajas Complejidad al tener que implementar el parser + compiler Disasociacin del lenguaje base o de ejecucin. Caemos fuera de las herramientas tradicionales, y perdemos soporte a nivel IDE (salvo, ahora con xtext)Artculo sobre cmo hacer un DSL externo usando XText" + +} , + +{ + +"title" : "Efectos y diseno", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/efectos-y-diseno.html", +"date" : "", +"content" : "Entendemos por efectos (colaterales) a aquellas modificaciones observables sobre el ambiente que son producidas por, y persisten tras, la ejecucin de un programa.Son ejemplos de efectos: la impresin de un mensaje por consola o un cuadro de dilogo en una interfaz grfica la asignacin destructiva de una variable en un programa procedural el encendido de una lmpara o la apertura de una compuerta La eliminacin de un registro en una base de datos El envo de un correo electrnico.En un sentido amplio, no es posible eliminar completamente los efectos: un sistema (software o no) que no presente efecto no ser capaz de transformar su entorno, y por lo tanto, ser intil completamente: por ejemplo de nada sirve generar un informe sobre contaminacin del agua si luego este no es tomado en cuenta en los controles.Por el contrario, los sistemas reales modifican de forma observable su mundo, recopilando informacin y actuando.Al hablar de efectos, es importante remarcar la importancia del observador, el nivel de detalle y alcance al que estamos analizando el problema. Por ejemplo, la impresin en papel de un informe, desde el punto de vista de la cola de impresin es una operacin con efecto, pero desde el punto de vista de un gerente, no lo tiene en tanto no llegue a sus manos y se tomen acciones en base a su contenido. Desde el punto de vista del microprocesador, una simple suma tiene efecto en tanto implica modificaciones en sus registros.Aqu solo consideraremos como efectos aquellos que sean observables por o mas all de nuestro cdigo, dejando fuera todo aquel efecto completamente encapsulado en el motor, como la Mquina Virtual de Java, o el intrprete GHCLa programacin OO tradicional permite y fomenta el uso de efectos. Los objetos responden a mensajes, eventualmente produciendo efectos, y son responsables tanto de generar como controlar estos efectos ordenando su ejecucin y protegiendo su estado interno.La programacin funcional en su forma ms bsica, en cambio, se trata de resolver los problemas en trminos de aplicacin de funciones puras, es decir, desprovistas de efecto. Entonces, si decimos que los efectos son necesarios, que beneficio nos puede reportar la programacin funcional?En primer lugar, porque que los programas con efectos son ms difciles de desarrollar y probar: los efectos no se ven en el cdigo y no pueden ser trazados facilmente, a diferencia de un valor etiquetado, que es fcil de encontrar y predecir su comportamiento independientemente del lugar donde se encuentre. En un programa puro, si la expresin:objeto.mensaje(argumento)resulta en la evaluacin de f(objeto, argumento), entonces siempre la primera expresin puede ser reemplazada por la segunda (transparencia referencial). Como caso particular, a iguales argumentos, igual resultado. Adems asegura que la evaluacin de cualquier otra expresin no habr sido modificada por esta. Ninguna de ambas afirmaciones son verdaderas en un programa con efectos.Disear un programa con efectos agrega entradas y salidas omnipresentes e invisibles; los datos viajan de forma global y las transformaciones ocurren en el tiempo. Su manejo se vuelve crtico cuando nuestro cdigo se ejecuta en mltiples hilos, o ante la presencia de excepciones.Afortunadamente, an es posible disear programas o partes de programas desprovistos de efectos, como parte de sistemas mayores: una calculadora, un compilador, un motor de reglas de un filtro de correo, son algunos de los infinitos programas que pueden ser modelados sin efecto.En OO existe una tendencia tendencia natural pero errada de forzar las responsabilidades y relaciones entre los objetos imiten a las del mundo real, perdiendo de vista que el objetivo de un sistema oo normalmente no se trata de simular sino resolver problemas, y en ocasiones las soluciones que se apartan de la realidad son igualmente simples de entender, y ms fciles de implementar y mantener. Esta malinterpretacin lleva a que los objetos tambin presenten cambios de estado superficiales, aun cuando, como sealbamos antes, podran haber realizado la misma tarea sin ste.La programacin funcional entonces nos permite mejorar nuestros diseos de objetos, al eliminar los efectos innecesarios.En segundo lugar, porque an en el uso de los efectos, es posible y en ocaciones desaeable un tratamiento a ms alto nivel del los mismos. Una de las fortalezas de los objetos es su capacidad, comparada con la programacin procedural, para la construccin efectos controlados y ordenados pero si bien triunfa al controlar la generacin de efectos, falla al intentar separar su generacin de su evaluacin, al cual ocurre indefectiblemente en el mismo momento. La programacin funcional nuevamente nos provee estrategias para cosificar (reificar) a los efectos, transformndolos en valores, y dandole el poder de controlar los efectos a incluso a aquellos objetos que no lo generaron.Ejemplo:snd(putStr"",putStr"foo")Por ltimo, una consecuencia interesante del asilamiento de los efectos es que conlleva una modularizacin del cdigo" + +} , + +{ + +"title" : "El papel del diseno en la metodologia de desarrollo", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/el-papel-del-diseno-en-la-metodologia-de-desarrollo.html", +"date" : "", +"content" : "El diseo cumple un rol fundamental en todos los desarrollos de software. Es entonces cuando tenemos que tomar decisiones que afectan directamente al producto que vamos a construir. Por supuesto, el qu del anlisis vs. el cmo del diseo es una diferencia que aparece en todos los libros. Pero mientras en el qu del anlisis las recomendaciones generales apuntan a ordenar, clasificar, separar en lo que es parte del sistema de lo que no lo eso bien, en encontrar los actores e identificar los requerimientos funcionales y no funcionaleso en discriminar requerimientos imprescindibles para la puesta en produccin de los importantes o deseablesen el diseo necesitamos echar mano a herramientas mucho ms cercanas a la tecnologa.Qu es disearDisear es encontrar: los componentes de un sistema la responsabilidad de cada componente (que justifica su existencia) y la relacin que cada componente tiene con los dems (sea temporal o ms permanente en el tiempo)Para eso tenemos que tomar decisiones, y aqu es donde empezamos a depender de la tecnologa, porque ella nos define: sus abstracciones cmo modelo cada componente o entidad? cmo defino comportamiento? puedo abstraer ese comportamiento? cmo relaciono las entidades? debo distinguir el medio en donde esas entidades estn relacionadas? sus limitantes sus beneficiosEl diseo y la metodologaSi la metodologa de trabajo es secuencial, cada fase del proyecto tiene un comienzo y un fin especfico. El diseo debe respetar el orden que le corresponde: despus del anlisis y antes de la programacin / construccin. Si la metodologa de trabajo es iterativa, esto implica disear en diferentes momentos, sin acotarlo a un perodo determinado.De la misma manera, cuando la metodologa es orientada al proceso, se genera una gran cantidad de documentacin respaldatoria del diseo. El proceso es el eje central del proyecto, que gua al objetivo que se quiere alcanzar (en el diseo esto se concreta con un documento entregable que es la especificacin). Si el proceso est bien definido slo hay que controlar el avance de las tareas. cuando la metodologa es orientada al producto final, nos interesa ms dejar en claro las decisiones importantes que respalden el software que est corriendo. La interaccin entre las personas es fundamental y termina definiendo el proceso de diseo, de la misma manera que el xito o el fracaso del mismo.Diseo anticipado y diseo iterativoLa metodologa de desarrollo nos lleva a disear de dos formas completamente diferentes:Las metodologas predictivas proponen el diseo anticipado, donde se asume que el anlisis ya ha relevado todos los procesos que el usuario necesita tenemos disponible toda la informacin para poder definir cada proceso no habr cambios en los requerimientos hasta nuestra implementacin el usuario no har cambios o nuevos pedidos. no habr cambios externos al sistema que obliguen a modificarlo (como disposiciones legales). si el diseo es adecuado, la codificacin se ajustar perfectamente a lo que el usuario necesita. para ello hay que documentar el sistema en su completitud para que los programadores no tengan que tomar decisiones de diseo en la codificacin. en la fase de diseo no se debe programar, dado que se estara solapando la actividad (de la misma manera que en la fase de codificacin no se debe disear)Por el contrario, las metodologas adaptativas proponen el diseo iterativo, donde se asume que slo tenemos algunos procesos relevados, y aunque los tuviramos en su totalidad, los requerimientos podran cambiar. es inocente pensar en que no habr cambios en los requerimientos, dado que el usuario no sabe exactamente lo que se va a construir y tiene derecho a pedir modificaciones cuando se da cuenta de que cometi un error al dar informacin al diseador. bajo la premisa anterior el diseador no puede realizar un diseo que no est sujeto a cambios, por los errores propios que adems podra cometer. si el diseo no es adecuado, debemos cambiarlo lo ms pronto posible. Esto incluye la fase de codificacin. si queremos reflejar la realidad, tenemos que permitir que haya alternancia entre diseo y programacin. No paralelizamos las actividades, sino que una se va solapando a la otra, como en una pila. el diseo iterativo considera que los errores son parte del desarrollo mismo y necesitamos poder modificar el diseo en cualquier momento, sin que eso paralice el proyecto (iterativo tiene mucho de prueba y error).Anlisis comparativoLos defensores del diseo anticipado sostienen que en el diseo iterativo se pierde el orden, que es difcil de coordinar un proyecto (no se sabe exactamente en qu porcentaje est cumplida cada actividad), y que el diseo iterativo confunde diseo y programacin, al punto en el que en realidad slo se programa.Los defensores del diseo iterativo creen en que todos los proyectos se construyen de esta manera, lo nico que hacemos al utilizar esta metodologa es reflejar lo que sucede en la realidad: los requerimientos cambian (aparecen nuevos, se modifican los existentes y algunos incluso desaparecen durante el proyecto), los diseadores se equivocan, tambin lo hace el usuario y continuamente nos vemos obligados a adaptar nuestra planificacin. Separar un proyecto en varias iteraciones facilita aceptar esos cambios, porque no se mantienen fijos los requerimientos ni los diseos, solamente mantenemos el plazo de entrega (lo que vamos a entregar est sujeto a cambios en cada iteracin).Pensar y hacerAl hacer la comparacin entre las metodologas orientadas al producto vs. las orientadas al proceso y al ver la enorme diferencia entre el diseo predictivo y el iterativo, se pone sobre la mesa una larga discusin: es correcto asociar los tiempos de diseo y programacin a los tiempos donde se piensa y donde finalmente se hace? es tan taxativa la diferencia? puedo abstraer los detalles tcnicos para disear una solucin? debe ocurrir primero la documentacin y despus la construccin o son tareas que pueden solaparse? es necesario contar con dos perfiles diferenciados, o sea, un analista funcional y otro programador? no sera ms sano tener un desarrollador senior con mayores capacidades de abstraccin y otro con menos experiencia, que pueda formarse en la materia?La metodologa define la discusin filosfica de si nos interesan ms las personas o los procesos. Asumir que el proceso tiene la prioridad presupone que slo tengo recursos para asignar, y si divido perfiles en personas que piensan (diseadores) de las que hacen o ejecutan (programadores) eso permite intercambiar gente sin mayores inconvenientes. Si pienso que las personas son importantes, que su grado de experiencia, la relacin entre s, la motivacin personal y grupal, la capacidad de aprendizaje y la respuesta ante problemas que surgen son la clave de xito de un proyecto, no nos interesa hacer la distincin entre pensar y hacer, porque esto ocurre todo el tiempo en forma simultnea, y mientras menos quiera disociar estos eventos (pensar y hacer) menos complicaciones tengo para encontrar un diseador que slo disee y un programador que slo programe. Adems el programador se transforma en una persona crtica del diseo, diseo que entonces puede mejorarse (es una metodologa menos rgida en este sentido).Integracin de las actividades de diseo en el proceso de desarrolloQu actividades ocurren al disear? Interactuamos con el usuario para repreguntar o proponer alternativas a lo que l solicit Interactuamos con el equipo de desarrollo, en donde pueden surgir inconsistencias en las definiciones que no habamos detectado antes: en el diseo iterativo este inconveniente est previsto, no as en el diseo anticipado en donde el equipo del proyecto debe asumir el costo de este imprevisto. dificultades tcnicas de implementacin: esto suele ser ms frecuente de lo que imaginamos, ya sea porque subestimamos la dificultad de un requerimiento, porque no tuvimos en cuenta algn factor tecnolgico o porque los imprevistos suceden en todo proyecto. Mientras que las metodologas secuenciales ven que el anlisis condiciona el diseo y ste a su vez define las decisiones de implementacin, es interesante notar que en los casos que mencionamos arriba es al revs: la arquitectura (o ms general, las cuestiones tcnicas) impactan sobre el diseo y el diseo puede hacer variar lo relevado en el anlisis. De hecho, este es el valor agregado de un buen diseador: hacer las preguntas que disparen mejoras en lo que el usuario pide.Links relacionados Volver a Diseo de Sistemas" + +} , + +{ + +"title" : "Uso del signo pesos ($) en haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/el-signo-pesos-en-haskell.html", +"date" : "", +"content" : "El signo pesos en Haskell (el $) se usa para 2 cosas:1- La funcin aplicar$ es la funcin aplicar. Hacer even $ 4 significa al even aplicalo pasndole el 4, o sea que es lo mismo que hacer even 4. Se suele usar para componer y hacer algunas cositas chetas como por ejemplo:Ejemplo, si en la consola quiero usar la funcin pam as:Prelude&gt; pam 5 [even, even, odd][False, False, True]Es decir, que de una lista de funciones quiero aplicarlas a un valor dado, podra resolverlo as:pam :: a -&gt; [(a -&gt; b)] -&gt; [b]pam cosa funciones = map (&#92;f -&gt; f cosa) funciones-- otra forma:-- pam cosa funciones = map (aplicarA cosa) funciones-- aplicarA cosa funcion = funcion cosao bien aprovechar la funcin $:pam :: a -&gt; [(a -&gt; b)] -&gt; [b]pam cosa funciones = map ($ cosa) funcionesAh aprovechamos la aplicacin parcial de $ (la aplicacin parcial de la funcin aplicacin ) para pasarle la cosa que necesita y luego que le falte recibir la funcin. Luego el map hace la magia de irle pasando todas las funciones de la lista.2- Evitando parntesisLa funcin$ tiene muy poca precedencia. Eso significa que a veces la gente la usa para evitar parntesis.Por ejemplo, esto est mal:even 2 * 3Porque even tiene ms precedencia que el * , eso significa que va a hacer even 2 y luego multiplicarlo por 3, lo cual es error de tipos.Entonces, hay que poner parntesis:even (2 * 3)O bien usar el $ :even $ 2 * 3Aprovechando que eso significa al even aplicalo pasndole el 2*3, y que como tiene muy poca precedencia, hace que todo lo que est a la izquierda se considere una cosa (el even), que todo lo que est a la derecha (el 2 * 3) se considere otra y entonces a even le aplica el resultado de 2*3.Es un clsico problema de sintaxis, de parsers. Cada lenguaje tiene sus reglas de precedencia para desambiguarlo, Haskell tiene las suyas, y se usa el $ como chiche a veces para evitar parntesis." + +} , + +{ + +"title" : "Elementos teoricos para comparar tecnologias de presentacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/elementos-teoricos-para-comparar-tecnologias-de-presentacion.html", +"date" : "", +"content" : "Clientes livianos y pesadosIntroduccin a los conceptos de cliente y servidorSi una aplicacin es accedida por mltiples usuarios simultneamente, probablemente cada uno de ellos lo haga desde su propia computadora en forma remota. Al programa que se ejecuta en la mquina del usuario se lo denomina cliente.Luego, esos clientes necesitarn poder compartir informacin entre s; en muchos casos esa informacin se centralizar en una o ms programas que se denominan servidor (en ingls server).La forma de repartir responsabilidades entre clientes y servidores dan lugar a un primer nivel de clasificacin de las posibles arquitectura de una aplicacin. Desde el punto de vista de la teora de presentacin, el punto ms interesante ser el cliente, ya que ser el que tenga la responsabilidad de interactuar con el usuario.Clasificacin tradicionalTradicionalmente se sola clasificar a los clientes entre pesados y livianos. Segn esa clasificacin, un cliente pesado tiene las siguientes caractersticas: Se instala en la mquina cliente. Es un programa independiente y completo (en ingls stand alone, esto es, no requiere de la presencia previa de otros programas en la mquina en la que se va a ejecutar (como mquinas virtuales, intrpretes, application clients, etc). Est pensado para ser utilizado en un entorno de ejecucin especfico (hardware, sistema operativo, etc) y eso le permite aprovechar todos sus recursos sin limitaciones. Por ejemplo: Se pueden utilizar todos los perifricos de la mquina como ser impresoras o cualquier dispositivo especfico. No hay limitaciones en cuanto a las formas de presentar la informacin o de interactuar con el usuario. Contiene gran parte o toda la lgica de la aplicacin, requiriendo pocos servicios del servidor, que se limita a ser un repositorio central de informacin. Requiere grandes cantidades de recursos de la mquina cliente.Los clientes livianos se caracterizan por delegar gran parte de la lgica de la aplicacin a la mquina servidora y de esa manera requerir menor cantidad de recursos de la mquina cliente. Sin embargo hay otra caracterstica de un cliente liviano que cambia radicalmente la forma de pensar las aplicaciones y es la aparicin del concepto de application client.El application client es un entorno en el cual se ejecutan las aplicaciones clientes de forma controlada, les da servicios que permiten simplificar la programacin de las mismas y tambin tiene polticas que permiten proteger a la mquina de posible cdigo malicioso. El application client ms ampliamente conocido es el web browser, pero no es el nico.La ejecucin dentro de un application client tiene gran impacto sobre las aplicaciones construidas de esta manera: El application client se ocupa de obtener dinmicamente el cdigo de la aplicacin, eliminando la necesidad de instalacin y de actualizacin de versiones. La aplicacin ya no es independiente y slo puede ejecutarse en una mquina que contenga el application client correspondiente, esto nos lleva con frecuencia a no utilizar el application client que podra ser ms til a nuestros propsito sino a amoldarnos al que es ms probable de encontrar instalado en las mquinas en las que querremos ejecutar nuestro programa. Permite que la misma aplicacin se ejecute en mquinas totalmente distintas, en tanto tengan el mismo application client. Restringe las posibilidades de uso de la mquina a lo provisto por el application client. Por ejemplo en el caso de una aplicacin web, tradicionalmente las aplicaciones estuvieron limitadas a la utilizacin del lenguaje HTML, lo que limitaba en gran medida las posibilidades de interaccin con el usuario.Evolucin de los tipos de clienteCon el tiempo la clasificacin taxativa entre clientes pesados y livianos se fue diluyendo y fueron apareciendo opciones intermedias. Desde ambos lados fueron apareciendo herramientas que intentaban incorporar en uno de los mundos algunas de las ventajas del otro.Application ClientsEn un primer lugar la universalizacin del concepto de Virtual Machine o la popularizacin de diferentes lenguajes interpretados hace que sea difuso cundo una aplicacin es stand alone o est utilizando un application client. Por ejemplo, una aplicacin Java puede verse como un cliente liviano que se ejecuta sobre un application cliente preinstalado (la JVM) o bien ver a ambos como un programa instalable nico. En definitiva es una cuestin de como se distribuye el programa, ya que hoy en da no existen practicamente lenguajes que no requieran de un intrprete, mquina virtual o determinadas bibliotecas instaladas previamente para poder ejecutar programas.El cuadro se completa cuando se incorporan herramientas para actualizar cdigo dinmicamente en lenguajes tradicionalmente pensados para aplicaciones pesadas como Java (Java WebStar).Inclusive la utilizacin de application clients se ha extendido a nuevos entornos, entre ellos podemos mencionar dos: Firefox y Eclipse, en ambos casos encontramos un entorno base o microkernel que provee de un entorno para la ejecucin de aplicaciones y una arquitectura basada en plugins o add-ons, que son los que en ltima instancia dan forma a la aplicacin.Rich Internet ApplicationsPor otro lado la popularizacin de las aplicaciones en Internet se contrapone con la gran cantidad de limitaciones que impone el HTML como lenguaje base para modelar las interfaces de usuario de dichas aplicaciones. Eso fue dando lugar a la aparicin de mltiples tecnologas que intentan sobreponerse a dichas limitaciones, algunos ejemplos son: La posibilidad de ejecutar JavaScript dentro del web browser permite tener comportamiento en el cliente que ya no se delega en el servidor. Manipular los componentes visuales desde ese cdigo JavaScript en el cliente, para salir de las limitaciones impuestas por el HTML. La incorporacin de tecnologas como AJAX permiten romper la metafora navegacional definida originalmente por el browser.Adicionalmente, la aparicin de herramientas como Flash, Applets, SVGs y HTML5 incorporan nuevos application clients que rompen la visin original del browser-intrprete-de-HTML.A las aplicaciones que salen de las limitaciones de navegacin, interaccin y visuales que tenan las aplicaciones web tradicionales se las denomina Rich Internet Applications (RIA) y por extensin tambin a las tecnologas que permiten desarrollar ese tipo de aplicaciones (se podra sumar tambin JavaScript a esta lista). Si bien se podra decir que este tipo de ideas estn an en evolucin, se observa una tendencia a tener application clients cada vez ms poderosos.Uso de RecursosTanto la aparicin de applications clients cada vez ms poderosos y complejos como la intencin de agregar dinamismo y comportamiento a los clientes han producido un incremento considerable en la cantidad de recursos que requiere una aplicacin web, habiendo en muchos casos prcticamente ninguna diferencia entre un cliente pesado y un cliente liviano.Descripcin de la vistaOtro de los elementos importantes a analizar al comparar tecnologas de presentacin son las herramientas que cada tecnologa propone al tiempo de definir una vista.Los conceptos fundamentales al describir una vista son los de componente y layout. Los componentes constituyen los elementos activos de la vista, es decir, aquellos con los que el usuario puede interactuar. El layout es la estrategia que indica cmo organizar los componentes espacialmente para poder visualizarlos.Si bien algunos frameworks modernos se denominan a s mismos orientados a componentes se puede considerar que en realidad la amplia mayora de las tecnologas de interfaz de usuario estn constituidas por componentes. La diferencia est entonces en la forma de describir esos componentes y su disposicin espacial, que se puede clasificar entre:ProgramticaSe basa en la manipulacin directa en el programa de los componentes visuales que conforman la vista.DeclarativaEn la que se utiliza un lenguaje de ms alto nivel que describe caractersticas de la vista pero sin indicar el algoritmo para su construccin o sin manipular los componentes visuales directametneVisualQue permite escojer los componentes de una paleta y visualmente organizarlos en la pantalla sin necesidad de programar o escribir prcticamente nada de cdigo.Model drivenEn la que la interfaz de usuario est guiada por el modelo de dominio y no se necesita programar especficamente (o se reduce notablemente la necesidad de programarla).Otra dimensin del anlisis a realizar pasa por los bloques de construccin de que disponemos, por ejemplo: De qu componentes disponemos y si es posible agregar nuevos componentes. Qu formas de layout estn contempladas. Qu mecanismos de interaccin tiene el usuario predefinidos con esos componentes.Mecanismos de descripcinMecanismos programticosHerramientas disponiblesComponentesHay un conjunto de componentes bsicos que suelen estar disponibles en todas las tecnologas, que incluyen: Campos para ingresar texto, pueden ser de una lnea o multilnea. Selectores entre varias opciones (combos, option buttons, etc). ueden ser de seleccin simple o mltiple. Check boxes (para seleccionar o no una opcin, combinando varios se puede formar un selector mltiple). Diferentes variantes de botones. Y otros controles informativos como ser labels o imgenes.Posibilidades de interaccinTambin se deben analizar las posibilidades de interaccin con esos elementos como por ejemplo: Qu eventos se pueden obtener de cada control, es decir, clickear sobre el control, modificar su valor, apretar una tecla, movimiento del mouse, etc. Drag &amp; drop.Layouts Fijo xy. tabsComponentes Diferentes formas de describir una vista: programtica, declarativa, visual, model driven. Diferencias entre diferentes variantes de declaratividad, scriptlets, etc. Manipulacin de componentes vs. manipulacin de texto. Navegacin Formas de navegacin: pantallas y formularios, ventanas y dilogos (o SPI), manipulacin directa. Control de la iniciativa: usuario o aplicacin. Integracin con el dominio de la aplicacin: stateless (basada en servicios) o statefull (basada en objetos y en eventos). Modelado Estado conversacional: en el cliente, en el server (sesin), en el pedido, en objetos especficos (por ejemplo: caso de uso). Integracin de la lgica: eventos y bindings (nivel de campo), formulario o pantalla (submit), objetos especficos (por ejemplo: caso de uso). Arquitecturas: orientado a la presentacin, datos, servicios, objetos." + +} , + +{ + +"title" : "Encapsulamiento", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/encapsulamiento.html", +"date" : "", +"content" : "Qu es el encapsulamiento?Quien usa un objeto slo ve lo que necesita para poder interactuar con l, que es el comportamiento que exhibe. Los detalles internos quedan encapsulados en el objeto. As quedan acotadas y explicitadas las formas posibles de interactuar con un objeto.El ocultamiento de detalles de implementacin, como ser los atributos de un objeto, permite separar mejor las responsabilidades y evitar efectos inesperados como resultado de la modificacin del valor de las variables por entidades externas.El uso de setters y getters (mensajes para modificar y conocer el valor de un atributo respectivamente), tambin conocidos como accessors, es importante para que el objeto que tiene esos atributos pueda controlar el uso de los mismos y para que los que usan al objeto que los tiene no sufran un impacto muy grande si la implementacin del mismo cambia.EjemploSupongamos que representamos a los lugares a los que puede volar nuestra amiga Pepita la golondrina como objetos que conocen su kilometraje en una ruta y nos saben decir a qu distancia se encuentran de otro lugar. Si su estado interno se modificara de modo que su ubicacin se represente por una coordenada (x e y), slo los lugares deberan verse afectados por este cambio ya que a Pepita slo le interesa conocer la distancia entre dos lugares.A medida que el sistema crece esta caracterstica toma ms importancia ya que no es fcil determinar todos los lugares en los cuales algo se est usando y qu impacto tiene ese uso.Es importante entender que acceder a los atributos de un objeto mediante mensajes no es suficiente para afirmar que no se rompe el encapsulamiento del objeto. Supongamos que queremos calcular la distancia que tiene que volar pepita para llegar a otro lugar, es muy comn ver cosas como:Smalltalk:pepitalugarActualkilometraje-otroLugarkilometrajeWollok:pepita.lugarActual().kilometraje()-otroLugar().kilometraje()(donde lugarActual y kilometraje son los getters de los respectivos objetos receptores) para trabajar con el nmero resultante en vez de delegar en el objeto que puede resolver el problema de la distancia a otro lugar. Si bien slo se estn usando getters, al preguntarle el kilometraje al lugar cuando lo que nos interesaba era la distancia nos estamos acoplando a cmo representa su ubicacin, y por ende si se quisiera cambiar a coordenadas, los usuarios del mensaje kilometraje se van a ver afectados." + +} , + +{ + +"title" : "Entradas al proceso de diseno", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/entradas-al-proceso-de-diseno.html", +"date" : "", +"content" : "Ralph &amp; Wand definen que el diseo clasifica las entradas o influencias al proceso de diseo en requerimientos, objetivos, componentes primitivas, restricciones y entorno.RequerimientosLos requerimientos o requirements son la entrada ms obvia y tal vez la ms importante. La fuente de los requerimientos es el proceso de anlisis, el anlisis tambin es una especificacin: de lo que el sistema debe ser, de sus caractersticas externas. El diseo especifica cmo el sistema debe construirse.La clasificacin ms comn de los requerimientos es dividirlos entre funcionales y no funcionales. Una buena especificacin de requerimientos debe contemplar tanto las cuestiones funcionales como las no funcionales, y el diseo deber proponer ideas.Requerimientos funcionalesLos requerimientos funcionales son las capacidades o funcionalidades de un sistema de software. Detallan el comportamiento del sistema. En otras palabras, lo que el sistema debe proveer. Hay distintos tipos de requerimientos no funcionales:Procesos de NegocioLos procesos de negocios permiten especificar como un proceso se lleva a cabo a travs de la organizacin, ya que requiere intervencin de diferentes actores y reas, en diferentes lugares y tiempos.Casos de UsoLos caso de uso definen una interaccin entre un actor y el sistema, para lograr un objetivo de negocio especifico en un lugar y momento especifico.Requerimientos no funcionalesSon los que especifican la forma en que el sistema debe llevar a cabo esas capacidades, determinan la calidad con la que el sistema brinda los servicios o bien la calidad con la que est construido.Objetivos (goals)Ralph y Wand diferencian un subconjunto de los requerimientos denominados objetivos (goals). Los objetivos resumen el impacto esperado del sistema en el ambiente.Componentes primitivas (primitive components)Son los bloques de construccin provistos por la tecnologa subyacente. En los niveles ms bajos de abstraccin del sistema, las abstracciones utilizadas tienden a coincidir con las herramientas provistas por la tecnologa, tanto en cuanto a sus bloques primitivos de construccin, como en la forma de combinarlos entre s.RestriccionesLas restricciones o constraints pueden tener diferentes orgenes: Tecnolgicas, tenemos que tener en cuenta qu cosas permite o no permite la tecnologa en la que vamos a construir el sistema. Leyes y otros reglamentos, incluyendo a los reglamentos internos de la empresa o licencias de las herramientas que usamos. Negocio, el negocio puede imponer restricciones de tiempo de llegada al mercado, costos y beneficios, tiempo de vida del sistema, entre otras. De arquitectura, la arquitectura puede imponer restricciones de integridad, correctitud, completitud, constructibilidad o robustez, entre otras.Entorno (Environment)Nos interesa tanto el entorno tecnolgico (con qu tecnologa contamos) como social (caractersticas de las personas que intervienen). Podemos diferenciar dos entornos:Entorno de desarrolloEs el ambiente en el que se disea, construye y/o prueba el sistema. Desde el punto de vista social debemos tener en cuenta sus conocimientos previos en cuanto a herramientas tecnolgicas, conceptuales y metodolgicas. Por ejemplo, antes de introducir una tecnologa nueva puede ser una buena idea analizar la capacidad del equipo para aprenderla. Desde el punto de vista tecnolgico debemos tener en cuenta por ejemplo los equipos con los que contamos para trabajar, si estn todos en un mismo lugar o separados, si la comunicacin (redes) entre esos lugares es buena o mala, si tenemos licencias de los programas que queremos usar, etc.Entorno de usoEl entorno en el que se usa el sistema. Desde el punto de vista social debemos considerar al usuario que esperamos, por ejemplo al disear la interfaz de usuario, o para instalarse el sistema en caso de ser necesario, sus costumbres previas, otros sistemas que usa.:*Desde el punto de vista tecnolgico podemos considerar el hardware del que puede disponer el usuario, su coneccin a Internet, etc." + +} , + +{ + +"title" : "Errores comunes usar un predicado como si fuera una variable", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/errores-comunes--usar-un-predicado-como-si-fuera-una-variable.html", +"date" : "", +"content" : "A veces se utilizan predicados unarios para representar verdades globales (lo que en otro paradigma sera una constante global).Por ejemplo podemos tener un predicado que nos diga la fecha de hoy:hoy(fecha(2009,10,15)).O podemos tener un predicado que refleje el estado del tablero en un domin:estado([ficha(0,1),ficha(1,4),ficha(4,2),ficha(2,2),ficha(2,5)]).El error consiste en utilizar hoy o estado como si fueran constantes, y no lo son.Ejemplo 1 - Fecha de hoySuponiendo que tengo en la base de conocimientos informacin sobre los downloads que se hicieron el da de hoy, en el predicado que relaciona un usuario, con un archivo bajado y una fecha; una forma incorrecta de utilizarlo sera:bajoAlgunArchivoHoy(Usuario):-download(Usuario,_Archivo,Fecha),Fecha=hoy.%INCORRECTO!La forma correcta de hacerlo podra ser:bajoAlgunArchivoHoy(Usuario):-download(Usuario,_Archivo,Fecha),hoy(Fecha).Se ve que en la nueva versin, hoy se utiliza como predicado y no como individuo.Ejemplo 2 - Estado del dominSi quiero saber los extremos de la lista que representa el estado del juego, es incorrecto hacer cosas como:extremo(E):-estado=[E|_].%INCORRECTO!!extremo(E):-ultimoLista(E,estado).%INCORRECTO!!La forma correcta de hacerlo sera:extremo(E):-estado([E|_]).extremo(E):-estado(Estado),ultimoLista(E,Estado).Asumiendo que el predicado relaciona a una lista con su ltimo elemento." + +} , + +{ + +"title" : "Errores comunes al comenzar a trabajar con haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/errores-comunes-al-comenzar-a-trabajar-con-haskell.html", +"date" : "", +"content" : "Variables mgicasAlgo que se ve mucho en los parciales es gente que inventa variables mgicas por no entender orden superior y aplicacin parcial, por ejemplo hacer algo como:aprobadosalumnos=filter(notaalumno&gt;4)alumnosen vez de:aprobadosalumnos=filter((&gt;4).nota)alumnoso en todo caso usando Expresiones lambda:aprobadosalumnos=filter(&#92;alumno-&gt;notaalumno&gt;4)alumnosLa variable alumno de la solucin errnea no existe, y si existiera estaramos cayendo en el problema explicado en la siguiente seccin.Funciones y valoresEs importante diferenciar: Qu valores son funciones y qu valores no. En qu lugares se espera poner una funcin y en qu lugares se espera otro tipo de valor.Por ejemplosonTodasPasablespelicula=all(puntajePromediopelicula&gt;6)(sndpelicula)tiene un error porque la funcin espera como parmetro una funcin, mientras que no es una funcin (denota un valor booleano)._ Otro ejemplo:puntajespelicula=sndpeliculaesRiesgosa=elem1puntajesCul es el problema? La funcin espera como segundo parmetro una lista, sin embargo la expresin no es una lista, sino una funcin que devuelve una lista.Moraleja: No es lo mismo un booleano/entero/string/etc que una funcin que devuelve un booleano/entero/string/etcComposicin y aplicacin parcialMuchas veces se ven errores que (a veces disfrazados de un me confund con los parntesis) llevan a expresiones invlidas, lo importante es entender qu construcciones son vlidas y cules no.Normalmente hay muchas formas de llegar al mismo resultado. Por ejemplo:(not.esDivisorao)100not(esDivisorao100)Estas dos lineas producen el mismo resultado. Mientras que las siguientes estn mal:not.esDivisorao100(not.esDivisor)ao100(otroBooleano&amp;&amp;(not.esDivisorao))100Porqu? Repasemos las que estaban bien:(not.esDivisor ao)100Lo que est resaltado es una funcin. Es resultado de componer otras dos funciones: not y esDivisor ao. Not como me refiero a esDivisor ao como una nica funcin, que NO es esDivisor. Para ver que son diferentes, podemos solo chequear sus tipos:'''esDivisor::Int-&gt;Int-&gt;BoolesDivisorao::Int-&gt;Bool'''Esta es una versin simplificada del tipo, no es exactamente lo que dira haskell, pero a efectos de la explicacin da igual. Not que esDivisor ao espera un argumento menos que esDivisor (justamente, porque ya le pasaste el ao). Obviamente, si aplicamos esta funcin otra vez, esto se repite.esDivisor ao 100 :: BoolEsto ya no es una funcin. Es un booleano. Ya no puedo aplicarlo.Habiendo entendido esto, miremos otra vez la composicin:(not.esDivisorao)Si digo que se est componiendo not con esDivisor ao, pods deducir que la aplicacin de una funcin tiene mayor precedencia que la composicin. Una forma de entender esto es que la aplicacin tiene prioridad, entonces la composicin va a trabajar con el resultado de la aplicacin.Comparemos esto con uno de los casos de error:(not.esDivisorao)100&lt;- Funciona bien. Le aplico 100 al resultado de la composicinnot.esDivisorao100&lt;- Falla! Trata de componer not con esDivisor ao 100, que es un Bool, no una funcin.Los otros casos erroneos tambin podemos deducirlos as:(not.esDivisor)ao100&lt;- Falla porque trats de componer esDivisor, que espera ms de un argumento.(otroBooleano&amp;&amp;(not.esDivisorao))100&lt;- Falla porque (not.esDivisor ao) es una funcin y &amp;&amp; espera un booleano." + +} , + +{ + +"title" : "Errores comunes con select y collect", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/errores-comunes-con-select--y-collect-.html", +"date" : "", +"content" : "Orden incorrecto entre collect: y select:Como se explica en Mensajes de colecciones, el select: es para filtrar una coleccin en base a un criterio mientras que el collect: es para recolectar los resultados de enviar un mensaje a cada objeto de la coleccin original.Supongamos que queremos obtener una coleccin con los promedios de los alumnos que aprobaron, podramos plantearlo como(alumnosselect:[:unAlumno|unAlumnoaprobo])collect:[:unAlumno|unAlumnopromedio]Si en vez de eso hicieramos(alumnoscollect:[:unAlumno|unAlumnopromedio])select:[:unAlumno|unAlumnoaprobo]Esto no va a funcionar, porque el collect: va a retornar una lista de nmeros, no de alumnos, con lo cual el filtrado no se va a poder hacer.Si lo que queremos es en cambio obtener los promedios &gt; 4 de los alumnos, ah no habra problema en hacer primero el collect: y luego el select:, porque el filtrado se hara sobre promedios y no sobre alumnos:(alumnoscollect:[:unAlumno|unAlumnopromedio])select:[:unPromedio|unPromedio&gt;4]Inicializacin inecesaria de variablesFjense una cosa: siempre que yo hago.a:=cualquiercosaEso es una asignacin destructiva s ya s, lo dije mil veces, pero lo que parece hasta ac fcil despus igual genera confusiones.Qu quiere decir eso de destructiva? Que se pierde lo que fuera que estaba referenciando la variable a, se pierde, o sea no me importa lo que tena la variable a antes de eso.Por qu saco a colacin esto ahora? Bueno el error que yo veo frecuentemente es este:a:=Setnew.a:=otroSetcollect:[...etc]Tiene sentido inicializar la variable a antes del collect:? Y no si yo en la siguiente lnea voy a hacer una asignacin destructiva justamente lo que sea que tiene la variable a se va a perder.Visto de otra manera, acurdense que dijimos el collect: me devuelve una coleccin NUEVA. Es decir, que no usa el valor de la variable a porque me devuelve una coleccin nueva.Y digo ms, si entends la asignacin, pods ver que primero se evala el lado derecho (lo que est despus del :=), y luego se asigna. Entonces a no interviene para nada en la evaluacin de otroSet collect: [ etc] (salvo claro que aparezca a en la expresin). Digo esto para desmitificar la idea de que de alguna manera el collect: podra dejar sus valores en el Set que apunta la variable a claramente eso no es posible.(Esa confusin puede que venga de programar en c, donde a veces yo necesito alocar memoria para que otro procedimiento deje datos en esa memora bueno, ac no es necesario alocar memoria, eso pasa solo! wiii! jaja. Adems que an en estructurado para que el proc pueda usar lo que yo aloqu debera pasrselo por parmetro y no como valor de retorno, esa caracterstica s es compartida.)Obviamente, el ejemplo del collect: vale para select: y todo mtodo que devuelva una coleccin. No?" + +} , + +{ + +"title" : "Errores comunes", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/errores-comunes.html", +"date" : "", +"content" : "Contenido del tag web-appThecontentofelementtype"web-app"mustmatch"(icon?,display-name?,description?,distributable?,context-param*,filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*,taglib*,resource-env-ref*,resource-ref*,security-constraint*,login-config?,security-role*,env-entry*,ejb-ref*,ejb-local-ref*)".El mensaje quiere decir que el contenido web-app es invlido, est mal formado.Para entender el mensaje, en la lista entre parntesis estn los posibles tags hijos de webapp, para solucionarlo habra que fijarse si tienen algo que est dependiendo de web-app y que no se ajuste a esa lista.Adems: Tienen que estar en el orden que estn en esa lista. Los que tienen ? son opcionales pero pueden 0 o una veces, los que tienen * pueden estar 0 o ms veces.Un error muy comn podra ser al tener varios servlets poner cada servlet con su servlet mapping y el estndar exige poner primero todos los servlets y recin despus todos los servlet mappings.En este caso puntual, es muy posible tener esa validacin en algn editor y que la aplicacin funcione de todas maneras, porque el tomcat no es estricto al chequear el formato del web.xml. La recomendacin es de todas formas ajustarse al estndar." + +} , + +{ + +"title" : "Errores en haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/errores-en-haskell.html", +"date" : "", +"content" : "Ver Paradigma_Funcional" + +} , + +{ + +"title" : "Errores frecuentes al programar en logico", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/errores-frecuentes-al-programar-en-logico.html", +"date" : "", +"content" : "Errores conceptuales ms importantes Confundir los conceptos del paradigma, por ejemplo: predicados con funciones - los predicados no devuelven cosas, tienen valor de verdad. Tenerlo en cuenta para la cantidad de parmetros y para no consultarlos mal variables con individuos (en particular tomos) - slo escriban variables con mayscula! predicados con individuos Errores lgicos propiamente dichos: Confundir Y con O Mezclar antecedente y consecuente en un forall Confundir existe con para todo (forall). Estilos de programacin no lgicos, por ejemplo: Utilizacin innecesaria de listas (ver errores comunes). Estrategias algortmicas. Programacin con efectos colaterales, por ejemplo intentos de asignar ms de una vez un valor una misma variable. Falta de abstraccin, que puede verse reflejada en: Uso de trucos programticos de bajo nivel, en lugar de representaciones abstractas de alto nivel. Ausencia de predicados auxiliares que abstraigan conceptos reutilizables en diferentes predicados de alto nivel (lo que normalmente lleva a la repeticin de cdigo). Malas deciciones a la hora de separar un predicado en subtareas, que llevan a tener predicados auxiliares que no representan abstracciones o conceptos tiles. Problemas de inversibilidad; ya sea por falta de generacin o por hacerlo incorrecta-/innecesariamente.Problemas generales de programacin Incumplimiento de las consignas. Cdigo que no se entiende, desprolijo, desordenado. Inconsistencias en general, por ejemplo: Las diferentes reglas de un predicado esperan parmetros con significados distintos. Una misma variable utilizada con diferentes objetivos inconsistentemente. Errores ms tcnicos Mal uso del pattern matching, en dos versiones: No aprovecharlo para quedarse con una parte de una estructura ms grande (functor o lista). Usar patrones demasiado especficos, perdiendo la oportunidad de construir predicados polimrficos. Usar igualdad (=) en lugar de is. -&gt; Explicacin: el = no resuelve cuentas. Es la igualdad ms trivial, la igualdad visual y directa de patrones y tomos. Usar el smbolo = en lugar de la misma variable, del individuo correspondiente.Cuestiones de estilo No elegir buenos nombres para variables y/o predicados. Utilizar pasos intermedios innecesarios que no aportan a la claridad del cdigo. No utilizar variables annimas donde corresponde. Complejidad innecesaria.Carteles de Error del SWI-Prolog Warning: Singleton Variables" + +} , + +{ + +"title" : "Escribiendo un paper", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/escribiendo-un-paper.html", +"date" : "", +"content" : "Un paper es un artculo de difusin cientfica. Dado el caracter cientfico del paper, la comunidad cientfica establece (quizs un poco ad-hoc) una cierta estructura y formato de estructura. En este artculo vamos a tratar la escritura de papers con un formato de tendencia _formal_.Para quienes quieran tener una breve introduccin, recomiendo vean el siguiente video:En ingls: https://www.youtube.com/watch?v=g3dkRsTqdDA Slides Formato de un paper El arte de buscar related work" + +} , + +{ + +"title" : "Esquemas de tipado", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/esquemas-de-tipado.html", +"date" : "", +"content" : "IntroduccinQu es un tipo?Toda expresin en un programa puede denotar diferentes valores en diferentes momentos (dependiendo del lenguaje eso puede ocurrir en la misma o en diferentes ejecuciones del programa). Un tipo describe un conjunto de valores. Al asignarle un tipo a una expresin se est delimitando cul es el conjunto de valores que podra denotar esa expresin.Por otro lado, las operaciones computacionales en general no pueden ser aplicadas sobre cualquier valor. Un sistema de tipos me provee una forma de estudiar qu valores tienen sentido para ser utilizados en una operacin dada. Por ejemplo, si x e y son valores numricos, la expresin x + y tiene sentido. En cambio si x e y son valores booleanos, x + y carece de sentido.La idea de tipo nos permite relacionar: un conjunto de valores que tienen ese tipo o son de ese tipo, con las operaciones que pueden ser realizadas sobre esos valores.Sistemas de tiposExisten diferentes tendencias en cuanto a cmo se clasifican a los diferentes lenguajes en funcin de la presencia o no de un sistema de tipos o de las caractersticas de ese sistema de tipos. Diferentes autores hablan de lenguajes tipados o no tipados, fuerte o dbilmente tipados, lenguajes estticos o dinmicos. Intentaremos proveer una forma de categorizacin que sea amplia para poder estudiar diferentes lenguajes y autores.Segn Luca Cardelli un lenguaje tipado es el que asocia cada expresin con un tipo (con uno no trivial). El sistema de tipos es el componente que administra la informacin de tipos de un programa. Un lenguaje se considera tipado por la existencia de un sistema de tipos, independientemente de que la sintaxis del lenguaje incorpore informacin de tipos.Los objetivos de un sistema de tipos son: Ayudar a detectar errores al programar. Guiar al programador sobre las operaciones vlidas en un determinado contexto, tanto en cuanto a documentacin com en cuanto a ayudas automticas que puede proveer por ejemplo un IDE. En algunos casos el comportamiento de una operacin puede variar en funcin del tipo de los elementos involucrados en la misma. De esto vamos a diferenciar varios sabores: polimorfismo, sobrecarga, multimethods, etc.Algunas caractersticas de un sistema de tipos: Proveen informacin al programador, de forma ms precisa que un comentario. Segn Cardelli, un sistema de tipos debera permitir hacer validaciones utilizando la informacin de tipos, algortmicamente. Las validaciones basadas en un sistema de tipos, que son ms fcilmente automatizables que otros tipos de especificaciones formales.Tipado implcito o explcitoEl tipado de Java es explcito, esto se ve en dos aspectos: Toda variable, parmetro, mtodo tiene un tipo definido. Para que dos objetos puedan ser polimrficos tengo que indicarlo explcitamente: herencia o interfaces.Las interfaces cumplen dos funciones: Permitir un polimorfismo chequeado estticamente y no restringido por la herencia simple. Ponerle nombre a un concepto que no quiero representar con una clase: documentar.En Smalltalk no necesito hacer una indicacin explcita de que dos objetos sean polimrficos, basta con que entiendan algn(os) mensaje(s) en comn. Vemos el ejemplo de los bloques y los smbolos.Chequeos estticos y dinmicosAlgunos ejemplos de cmo se comportan los tipos en Java y en Smalltalk En Java tomamos un String e intentamos mandarle el mensaje caminar, no compila: chequeo esttico. En Smalltalk hago lo mismo y me permite ejecutarlo, se rompe en tiempo de ejecucin: chequeo dinmico o en tiempo de ejecucin.Eso nos marca una primera categorizacin de los tipos: en funcin de en qu momento se chequean. No necesariamente un lenguaje tiene siempre el mismo comportamiento, en java si yo casteo postergo el chequeo hasta el tiempo de ejecucin. Si se acuerdan de lenguaje C, recordamos que ante un casteo puede pasar cualquier cosas: a veces simplemente no se valida nada.Esta primera diferencia parecera volcar la balanza a favor de los lenguajes con chequeo esttico, porque detectan antes los problemas, sin embargo vamos a ver que tambin tienen desventajas. Por otro lado, ante la presencia de casteos el chequeo esttico se pierde.Finalmente es importante diferenciar entre chequeo dinmico y no chequeo. El chequeo dinmico me permite manejar el problema y manejarlo o por lo menos me lo informa correctamente, la ausencia de chequeo suele causar errores muy difciles de detectar o corregir.Deteccin de erroresCardelli propone discriminar dos tipos de errores que se pueden producir durante la ejecucin de un programa:Trapped (atrapados)Son los errores que se detectan inmediatamente, por ejemplo una divisin por cero.Untrapped (no atrapados)Son errores que pueden no ser detectados. El programa podra continuar ejecutndose por un tiempo antes de detectar el problema. Esto puede ocurrir en algunos lenguajes por ejemplo si se accede a posiciones de un array ms all de su longitud o se salta a una posicin invlida de memoria.Un programa se considera seguro (safe) si no causa untrapped errors. Un lenguaje se considera seguro si todo programa escrito en ese lenguaje est excento de untrapped errors.En todo lenguaje se puede designar un conjunto de los errores como prohibidos. Los errores prohibidos deberan incluir a todos los errores untrapped, ms un subconjunto de los errores trapped. Un programa que no causa errores prohibidos se dice que tiene buen comportamiento (good behavior).En un lenguaje strongly checked, todos los oprogramas tienen buen comportamiento, es decir: No ocurren errores untrapped. No ocurren los errores trapped que se consideran prohibidos.Siempre queda a responsabilidad del programador evitar los errores trapped que no se eligieron como prohibidos.Tipos nominales y estructuralesEso nos lleva a una clasificacin ms: tipos estructurales vs. tipos nominales. Llamamos nominales a los tipos que tienen un nombre. En Java los tipos son nominales estn dados por las clases (concretas o abstractas) y por las interfaces. En Smalltalk los tipos son estructurales, por ejemplo todos los objetos que entienden #value son un tipo. La nominalidad del Java se ve en que si hago dos interfaces con los mismos mensajes, los objetos que implementan la primera no son polimrficos con los objetos que implementan la segunda.Algunas combinaciones posiblesSuele haber una fuerte relacin entre los tipos nominales-explcitos y estructurales-implcitos. Esto es porque uno para explicitarlos le pone nombre, pero en algunos lenguajes como Scala existen tipos estructurales y explcitos.Tambin suele haber una fuerte relacin entre el chequeo esttico y el tipado explcito o nominal, sin embargo en Haskell podemos ver que tenemos tipos implcitos y chequeo esttico. Normalmente esto va asociado a un concepto llamado inferencia de tipos, es decir, cmo se hace para poder chequear el tipo de algo sin que me lo digas? Tiene que poder inferirlo el compilador por s mismo.Y ac se ven las desventajas de los sistemas de tipado ms fuertes: Obligan a la burocracia de decir de qu tipo va a ser cada cosa y de indicar qu cosas pueden ser polimrficas. Muchas veces me restringen las posibilidades que tengo al programar.Gran parte del trabajo en sistemas de tipos que se hace intenta construir sistemas o lenguajes que puedan evitar errores minimizando la burocracia y/o eliminando las restricciones innecesarias.ClasificacionesEn resumen planteamos tres clasificaciones: En cuanto a la forma de chequeo puede ser esttico/compile time, dinmico/runtime o nada. En cuanto a la forma de especificar el tipo de algo puede ser explcito o implcito / inferido. En cuanto a la forma de constituir un tipo puede ser nominal o estructural (no s si agregar dependientes, tambin hay ms variantes).Ms complicada es la clasificacin en cuanto a los tipos de polimorfismo que se banca (en particular en los lenguajes con tipado esttico).Algunos ejemplos Java tiene un tipado esttico, nominal y explcito (en presencia de casteos se vuelve dinmico) Smalltalk es dinmico, estructural e implcito. Self lo mismo. Haskell es esttico pero se banca ser explcito o implcito (inferencia de tipos) y en algunos casos tambin se comporta estructuralmente. Scala es esttico, tiene algo de inferencia y tambin soporta tipos estructurales y nominales. ObjectiveC puede ser esttico o dinmico si usas los ids. C aparenta ser esttico, pero ante casteos yo veo que el tipado es nulo." + +} , + +{ + +"title" : "Estado identidad y diseno", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/estado--identidad-y-diseno.html", +"date" : "", +"content" : "Inmutable vs mutableDecimos que un objeto es inmutable cuando su estado es insignificante, o se mantiene constante a lo largo de su ciclo de vida, o, en una visin ms relajada, luego de su momento de nstanciacin.IdentidadEn el paradigma de objetos, estos componentes agrupan lo que en otros paradigmas en general est claramente separado: datos (estado) y comportamiento. Adems, los entornos de objetos los manejan mediante referencias (C++ es una excepcin notable), lo que nos lleva a otra propiedad fundamental: la identidad." + +} , + +{ + +"title" : "Estado y diseno", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/estado-y-diseno.html", +"date" : "", +"content" : " REDIRECCIN Estado, Identidad y diseo" + +} , + +{ + +"title" : "Estereotipos de objetos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/estereotipos-de-objetos.html", +"date" : "", +"content" : "Un objeto presenta presentan tres caractersticas fundamentales: Comportamiento: un objeto sabe hacer cosas, y eventualmente cada uno las podra saber hacer de distinta forma. Estado: un objeto mantiene relaciones con otros objetos, las cuales pueden cambiar a lo largo de su vida. Muchas veces, al compararlo con paradigmas donde dato y operacin son elementos claramente separados, es til pensar al estado como justamente la parte de datos. Identidad: un objeto es tratado mediante referencias, y puede ser distinguido de otro, aun cuando el otro presente el mismo estado y comportamiento.Los objetos existen en nuestro sistema para cumplir responsabilidades. Aunque normalmente asociamos fuertemente la idea de responsabilidad a la de comportamiento hay ocasiones en que nos convendr disear nuestros objetos de forma tal que expongan su estado e identidad.En base a estos tres aspectos del objeto, podemos ensayar la siguiente caracterizacin de los objetos: Entidades: Su identidad es importante (cuando tenemos que enviarle varios mensajes a uno de estos objetos, nos importa que el receptor sea siempre el mismo, y no tan solo uno parecido). Presentan estado significativo y mutable, y poco comportamiento, fuertemente acoplado a las caractersticas anteriores. Su cclo de vida es tpicamente largo. Son ejemplos tpicos de entidades aquellos objetos persistentes en una base de datos transaccional (aunque por motivos de implementacin, su identidad nativa puede perder algo de importancia, y se recurre al uso de atributos que modelan la identidad). Smbolos: Su identidad es importante, no presentan comportamiento ms que la comparacin por identidad (==) o quizs la representacin textual (toString). No presentan estado, o es inmutable. Se los emplea tpicamente para modelar cdigos, o elementos del metamodelo del lenguaje, como nombres de clases o selectores. Algunos lenguajes como Smalltalk o Ruby soportan nativamente estos objetos, mientras que en otros, como Java, se suple su falta con Strings Valores Servicios/Tareas: aquellos objetos con una fuerte carga de comportamiento independiente de su estado Objetos anmicos/DTOs Estereotipo Identidad Comportamiento Estado Entidad Importante Mucho Mucho y Mutable Simbolo Importante Poco Poco e Inmutable Valor Transparente Mucho Mucho e Inmutable Servicio - Mucho Poco DTO Importante Poco Mucho y Mutable Algunas combinaciones nos llevan a: Identidad importante, estado y comportamiento inexistentes: smbolos, candados. Identidad y estado importante: entidades Comportamiento importante, estado e identidad insignificantes: objeto funcin, stratey stateless,Comportamiento...Semntica de referencia vs semntica de valor Su identidad no es importante (Consecuencia de lo anterior) Su estado, si importante, es constante." + +} , + +{ + +"title" : "Estrategias de evaluacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/estrategias-de-evaluacion.html", +"date" : "", +"content" : "Estrategias de evaluacinIntroduccinLa operacin que realizamos en funcional es aplicar funciones, la idea del tema que vamos a tratar a continuacin es saber qu se tiene que tener en cuenta para determinar el orden en en que aplicarn las funciones de una expresin.Primer ejemplomasUnox=x+1La expresin masUno (2*3) puede ser evaluada de la siguiente formamasUno(2*3) aplicamos *masUno6 aplicamos masUno6+1 aplicamos +7Alternativamente podemos evaluar la misma expresin pero aplicando las funciones en el orden inversomasUno(2*3) aplicamos masUno(2*3)+1 aplicamos *6+1 aplicamos +7No importa el orden en que apliquemos las funciones vamos a llegar al mismo resultado final. Esto no solo vale para ejemplos sencillos sino que se cumple siempre en Haskell.Esta propiedad no se cumple en la mayora de los lenguajes imperativos (Pascal, C, Smalltalk, Java, C#, etc.), veamos un ejemplo en Smalltalk:Si tenemos la expresin n + (n := 1) y n empieza apuntando a 0.Si empezamos a evaluar de izquierda a derechan+(n:=1) aplicamos n0+(n:=1) aplicamos :=0+1 aplicamos +1Si empezamos a evaluar de derecha a izquierdan+(n:=1) aplicamos :=n+1 aplicamos n1+1 aplicamos +2Como se puede observar, si evaluamos las expresiones con distintas estrategias obtenemos resultados distintos; esto sucede porque las operaciones involucradas no tienen transparencia referencial en este caso particular debido a la introduccin de una asignacin destructiva.Estrategias bsicasA una expresin que consta de una funcin aplicada a uno o ms parmetros y que puede ser reducida aplicando dicha funcin la vamos a llamar Redex (Reducible Expression). Se le dice reduccin al hecho de aplicar la funcin no necesariamente vamos a obtener una expresin ms corta como veremos ms adelante. Consideremos la funcin mult que tiene como dominio una tupla de 2 nmerosmult(x,y)=x*ySi queremos reducir la expresin mult (1+2,2+3) est expresin contiene 3 redexs 1+2 (la funcin + aplicada a 2 parmetros) 2+3 (la funcin + aplicada a 2 parmetros) mult (1+2,2+3) (la funcin mult aplicada a 1 parmetro que es una tupla) Si queremos evaluar la expresin qu estrategia usamos?De adentro hacia afueraTambin conocida como call-by-valueUna de las estrategias ms comunes es comenzar desde adentro hacia afuera (innermost evaluation), esta estrategia elige el redex que est ms adentro entendiendo por esto al redex que no contiene otro redex. Si existe ms de un redex que cumple dicha condicin se elige el que est ms a la izquierda. Vamos al ejemplomult(1+2,2+3) aplicamos el primer +mult(3,2+3) aplicamos el +mult(3,5) aplicamos mult3*5 aplicamos *15Esta estrategia me asegura que los parmetros de una funcin estn completamente evaluados antes de que la funcin sea aplicada. Por eso se dice que los parmetros se pasan por valor.De afuera hacia adentroTambin conocida como call-by-nameOtra de las estrategias ms comunes es comenzar desde afuera hacia adentro (outtermost evaluation), esta estrategia elige el redex que est ms afuera entendiendo por esto al redex que no esta contenido en otro redex. Si existe ms de un redex que cumple dicha condicin se elige el que est ms a la izquierda. Vamos al ejemplomult (1+2,2+3) aplicamos mult(1+2)*(2+3) aplicamos el primer + (Si seguimos lo que dijimos arriba deberamos aplicar primero el * pero vamos a explicar porque no lo hacemos ms abajo)3*(2+3) aplicamos +3*5 aplicamos *15Usando esta estrategia las funciones se aplican antes que los parmetros sean evaluados. Por esto se dice que los parmetros se pasan por nombre. Nota: Hay que tener en cuenta que muchas funciones que ya vienen con Haskell requieren que sus parmetros estn evaluados antes de que la funcin sea aplicada, incluso cuando usamos la estrategia de afuera hacia adentro. Por ejemplo, el operador * y el + no pueden ser aplicados hasta que sus dos parmetros hayan sido evaluados a nmeros. A las funciones que cumplen con esta propiedad las vamos a llamar funciones estrictas. Funciones estrictas que nos van a interesar a nosotros: Operaciones aritmticas (+,*,/,etc.) Pattern-Matching (sobre listas, tuplas, etc.)Evaluaciones que no terminanTengan en cuenta la siguiente definicininf=1+infIntentar reducir la expresin inf siempre nos va a dar como resultado una expresin ms y ms grande (independientemente de la estrategia de evaluacin que usemos)inf aplicamos inf1+inf aplicamos inf (porque + es estricta)1+(1+inf) aplicamos inf (porque + es estricta).1+(1+(1+(1+(1+(1+....+inf)))))Por ende, est evaluacin nunca terminara.Sabiendo quefst(x,_)=xConsideremos la expresin fst (0,inf)Usando la estrategia call-by-valuefst(0,inf) aplicamos inffst(0,1+inf) aplicamos inffst(0,1+(1+inf)) aplicamos inffst(0,1+(1+(1+inf))) aplicamos infUsando call-by-value la evaluacin de la expresin no termina.Usemos call-by-name:fst(0,inf) aplicamos fst0Usando call-by-name la expresin se evala por completo con solo una reduccin. En este ejemplo se puede ver que ciertas expresiones que pueden no terminar cuando se evalan con la estrategia call-by-value pueden terminar cuando se usa la estrategia call-by-name.De forma ms general: Si existe alguna secuencia de evaluacin que haga terminar la evaluacin de la expresin entonces con la estrategia call-by-name tambin se termina la evaluacin y se produce el mismo resultado final.Corolario: si te es mucho muy importante que una expresin termine la estrategia que quers usar es call-by-nameLazy EvaluationVisin tcnicaSi tenemos la siguiente definicinalCuadradox=x*xVamos a evaluar la expresin alCuadrado (2*3) usando call-by-valuealCuadrado(1+2) aplicamos +alCuadrado3 aplicamos alCuadrado3*3 aplicamos *9Ahora vamos a evaluar la misma expresin usando call-by-namealCuadrado(1+2) aplicamos alCuadrado el primer +(1+2)*(1+2) aplicamos el +3*(1+2) aplicamos el *3*3 aplicamos el *9Llegamos la mismo resultado pero en el segundo ejemplo realizamos una reduccin ms (4 reducciones vs 3 reducciones).Con call-by-name la expresin (1+2) se evalu dos veces.Corolario: cuando usamos call-by-value los parmetros son evaluados una y solo una vez; cuando usamos call-by-name el mismo parmetro puede llegar a ser evaluado ms de una vez.Para evitar este quilombo en vez de tener la expresin (1+2) vamos a tener un puntero a la expresin llammoslo p.alCuadrado(1+2) aplicamos alCuadradoletp=(1+2)inp*p aplicamos +letp=3inp*p aplicamos *9Cualquier reduccin que se haga en una expresin se va a conocer automticamente por los punteros a dicha expresin. Al uso de punteros para compartir expresiones que representan la mismo parmetro lo vamos a llamar Sharing. Al uso de la estrategia call-by-name ms el Sharing lo vamos a llamar Lazy Evaluation (esta es la estrategia que usa Haskell). El Sharing nos asegura que usar Lazy Evaluation nunca requiera ms pasos que la estrategia call-by-value.Visin operativaA efectos de resumir lo que vimos hasta ahora vamos a entender lo siguiente Lazy Evaluation: con esta estrategia los parmetros solo se resuelven cuando son necesarios (y son evaluados solo lo necesario). Tambin conocida como evaluacin perezosa o diferida.A la estrategia call-by-value (y sus variantes) tambin se las conoce como Eager Evaluation. Eager Evaluation: con esta estrategia los parmetros tienen que resolverse antes de aplicar la funcin. Tambin conocida como evaluacin ansiosa.Estructuras infinitasPensemos en la siguiente definicinunos=1:unos(A partir de ahora vamos a pensar que evaluamos todo en Haskell as que la estrategia que usamos es Lazy Evaluation)unos aplicamos unos1:unos aplicamos unos1:(1:unos) aplicamos unosEn Haskell&gt;unos[1,1,1,1,1,1,1........Como se puede ver la evaluacin de unos no termina. A pesar de esto podemos usar la expresin unos dentro de nuestro programa y aplicarla a otras funciones. Por ejemploSiendo head (x:_) = x y la expresin head unosheadunos deberamos aplicar head pero como head me fuerza a tener la lista separada en cabeza:cola tenemos que evaluar unos por el pattern-matchinghead(1:unos) aplicamos head1Con este ejemplo podemos ver que unos no es una lista infinita sino potencialmente infinita, si aplicamos sobre ella funciones que no la fuerzan a evaluarse por completo la computacin termina (eso son apocalptico). La potencia de Lazy Evaluation est en que la expresin unos se evala solo lo necesario para que pueda usarla la funcin que la recibe como parmetro.Listas infinitasYa vimos la lista de unos que es infinita, ahora veamos como hacer una lista que tenga todos los nmeros naturalesnaturalesDesdex=x:naturalesDesde(x+1)&gt;naturalesDesde1[1,2,3,4,5,6,7,8,9,...........Haskell trae un atajo para estonaturalesDesdex=[x..]Tambin sirve para hacer listas con alguna condicin entre dos de sus elementos consecutivos&gt;[1,3..][1,3,5,7,9,11,.........Entonces si queremos obtener los primeros 24 mltiplos de 13 podemos hacerlo de esta forma:&gt;[13,26..24*13][13,26,39,52,65,78,91,104,117,130,143,156,169,182,195,208,221,234,247]Pero tambin podemos resolverlo con una lista infinita usando take como veremos a continuacin gracias a la evaluacin perezosa.&gt;take24[13,26..][13,26,39,52,65,78,91,104,117,130,143,156,169,182,195,208,221,234,247]EjemplosDada la siguiente definicin de taketake0_=[]take_[]=[]taken(x:xs)=x:(take(n-1)xs)take3[1..] aplicamos ..take3(1:[2..]) aplicamos take - 3ra lnea1:(take2[2..]) aplicamos ..1:(take2(2:[3..])) aplicamos take - 3ra lnea1:(2:(take1[3..])) aplicamos ..1:(2:(take1(3:[4..]))) aplicamos take - 3ra lnea1:(2:(3:(take0[4..])))) aplicamos take - 1ra lnea1:(2:(3:[])))=[1,2,3]Vamos a otro ejemplotake3[4+5,2/0,3*2] aplicamos el + (porque dice x: en take 3ra lnea)take3[9,2/0,3*2] aplicamos take - 3ra lnea9:take2[2/0,3*2] aplicamos /9:ERRORDIVISONBYZERO!!!Dada la definicin de (!!)(!!)0(x:_)=x(!!)n(_:xs)=(!!)(n-1)xs(!!)2[4+5,2/0,3*2] aplicamos el !! (no es necesario aplicar el + porque en (!!) dice (_:xs) )(!!)1[2/0,3*2] aplicamos el !! (no es necesario aplicar la / por lo anterior)(!!)0[3*2] aplicamos * (porque la primer lnea de !! lo pide)(!!)0[6] aplicamos !!6Supongamos que hacemos esta consulta:&gt;head(filter(3&lt;)[1..])Si bien la expresin filter (3&lt;) [1..] no termina (seguira buscando cules son mayores a 3 infinitamente), como lo que primero se evala es el head y se difiere la ejecucin del filtrado, la ejecucin va a terminar en cuanto el filter encuentre su primer elemento que pertenezca a la solucin que es el 4.Es importante notar que en este otro caso:&gt;head(filter(&lt;0)[1..])La evaluacin nunca termina por ms que se use head que era lo que antes acotaba la ejecucin, ya que nunca se va a encontrar el primer elemento que cumpla la condicin a diferencia del caso anterior." + +} , + +{ + +"title" : "Evaluacion diferida y diseno", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/evaluacion-diferida-y-diseno.html", +"date" : "", +"content" : " Como impacta al momento de hacer debug Como su aplicabildiad est limitada por los efectos Como simplifica el cdigo (ejemplo con hibernate?) como puede impactar negativamente o positvamente en el rendimiento Como se relaciona con LazyObject y FunctionObject" + +} , + +{ + +"title" : "Excepciones - Resumen avanzado", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/excepciones-avanzadas.html", +"date" : "", +"content" : "MaterialPueden ver un apunte completo en este linkFormas de manejar una excepcinPropagarlaEs una buena opcin cuando no se cmo salvar la situacin, e implica propagar la misma exception (declarando throws XXXException en la firma del mtodo) envolverla (wrappearla) en otra nueva, que agregar un mensaje de ms alto nivel. Ej:public void enviarResumenMensual(Cliente c) { try { String resumen = this.generador.crearResumen(c); this.clienteMail.enviarMail(c.getEmail(), resumen); } catch (EmailException e) { throw new ProgramException("Error al enviar el resumen por mail al usuario " + c.getNombre(), e); }}TratarlaCuando tengo un requerimiento especfico como: Si falla el servidor de mail, intentar con una lista de otros servidores alternativos. Si falla el servidor de mail, esperar 5 segundos y reintentar. Realizar esto unas 5 veces. Caso que siga fallando, abortar el envo con un mensaje.Buenas Prcticas Nunca catchear una exception para no hacer nada. No hacer nada tambin incluye el loggearla. Es decir, catchear para loggear y seguir adelante, debera sonar muy raro. Tal vez tenga sentido eso como requerimiento en un nico lugar de la arquitectura, para que no se caiga completamente la aplicacin. Pero en el 99% de las veces es una hackeada. En general wrappear para agregar informacin de contexto (qu estaba haciendo este mtodo al encontrar un error en otro al que llama) As al momento de fallar una operacin de negocio no terminamos con un solo mensaje puntual muy especfico que ser dificil de comprender para el usuario/administrador/programador, como No me pude conectar al host 12.23.22.12, si no una jerarqua de mensajes desde lo ms general a lo ms especfico como: Error al ejecutar el ciclo de facturacin -&gt; Error al facturarle al usuario numero 5963472 -&gt; Error al enviar el resumen mensual -&gt; Error al enviar el mail -&gt; No me pude conectar al host 12.23.22.12No olvidar de pasar la causa original del error al wrappear (en nuestro ejemplo, la referencia a travs de la variable e) Evitar try-catch dentro de otro try-catch: refactorizar la parte interna que puede fallar, llevndola a otro submtodo. Evitar cdigo antes y despus de un try-catch, llevando todo el cdigo a la formamtodo() { try { logica } catch}Es decir que el try-catch envuelva todo el cdigo del mtodo. Este va de la mano con la idea de hacer mtodos ms chiquitos. Al hacer una sola cosa, el mtodo solo puede tener un tipo de falla." + +} , + +{ + +"title" : "Excepciones", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/excepciones.html", +"date" : "", +"content" : "IntroduccinCuando un programa se ejecuta, pueden ocurrir errores: problemas de diversa ndole que hacen que el sistema se comporte de una forma no esperada: el usuario ingres un valor invlido, un objeto mal programado envi un mensaje con parmetros incorrectos, etc. Si el programa continuara ejecutndose ignorando esto, lo nico que lograramos sera que se produzcan ms errores, cada vez ms graves. Entonces, qu hacer ante un error?Lo ms seguro es fallar, es decir, abortar el flujo de ejecucin para impedir que el resto del programa contine ejecutndose como si no hubiera pasado nada. Una forma de lograr esto es mediante el lanzamiento de excepciones.En general cada mtodo desarrollado debera seguir las siguientes pautas: Tener un nombre descriptivo, ya que dicho nombre nos dice qu esperar, es una promesa al usuario de lo que debera suceder luego de mandar el mensaje Hacer todo y slo lo que el nombre indica Si por algn motivo no se puede cumplir con lo prometido por el nombre del mtodo, explotar de la forma ms prolija posibleEs importante que aquellas cosas que puedan ser validadas para saber si no se podr cumplir con lo prometido, se validen previamente a producir efectos colaterales, de esa forma podemos evitar algunas posibles inconsistencias en caso de poder seguir adelante manejando el problema de alguna forma.ExcepcionesUna excepcin es la indicacin de un problema que ocurre durante la ejecucin de un programa. La principal particularidad de las excepciones es que cortan el flujo de ejecucin hasta que alguien se encargue de resolverlo. Supongamos que tenemos este cdigo Wollok:object prueba { method msj1(){ self.msj3(self.msj2()) } method msj2(){ self.error("Todomal!") return "Estonosevaaejecutarnunca" } method msj3(string) = "Opa! " ++ string}De esta forma si el objeto que define esto recibe el mensaje msj1, la excepcin lanzada en msj2 cortar la ejecucin con lo cual no se evaluar la siguiente lnea ni se mandar msj3. Es correcto dejar que la excepcin se propague hacia atrs por la cadena de mensajes enviados siempre que no haya nada para hacer al respecto. Eventualmente, en algn punto donde s sea posible tomar alguna accin, se podr manejar esta excepcin y continuar la ejecucin con normalidad.Bugs vs Errores de usuarioAlgunos errores surgen por un bug en el programa, por ejemplo si un objeto no entiende un mensaje la forma de resolverlo es modificar el cdigo para que o bien lo entienda o el mismo no le llegue dependiendo de si debera o no entenderlo. Por ejemplo, si a un Set le pedimos el primer elemento tira un error porque no es una coleccin ordenada, por ende no debe responder al mensaje first como s lo hace una coleccin ordenada.Otros errores surgen del uso del programa, ya que pueden darse situaciones que llevan a que un objeto no pueda realizar lo que se le pide. Por ejemplo, si a una coleccin vaca el mandamos el mensaje anyOne tira un error porque no tiene forma de resolver el problema.Lanzando ExcepcionesEn Wollok la forma ms fcil de lanzar una excepcin es mediante un mensaje a self (en este caso error(descripcion)) que todos los objetos entienden. Por ejemplo:object pepita { var energia = 100 method vola(unosKms){ if(energia &lt; unosKms){ self.error("Energa insuficiente para volar los kilmetros requeridos") } energia = energia - unosKms }}En el ejemplo vemos que si la energa de pepita es menor a la cantidad de kilmetros pasados por parmetro, la operacin no debera realizarse porque quedara con energa negativa. Para evitar que eso pase se lanza el error con una descripcin simptica para que el usuario o el desarrollador (dependiendo de si debera o no llegarse a esa situacin) entienda qu fue lo que pas. Lo interesante es que la lnea que modifica la energa slo llega a ejecutarse si energia &gt;= unosKms.Otra forma de lanzar excepciones es usando clases pertenecientes a una jerarqua particular, que son de tipo excepcin. El ejemplo anterior podra reescribirse de la siguiente forma, usando DomainException que es el mismo tipo de excepcin que usa el mensaje error por atrs y hereda de la clase Exception:object pepita { var energia = 100 method vola(unosKms){ if(energia &lt; unosKms){ throw new DomainException(message = "Energa insuficiente para volar los kilmetros requeridos") // se usa la palabra reservada throw con la excepcin a lanzar } energia = energia - unosKms } ...}Esto as como est no tiene ninguna ventaja sobre lo anterior, que era bastante ms bonito y simple. Para que tenga sentido, tenemos que pensar en este problema en un contexto ms amplioCmo evitar que se rompa todo ante situaciones excepcionales?Algunos errores pueden evitarse realizando validaciones previas, pero no siempre es posible o deseable usar este enfoque. Entonces, una vez que se produce el error tenemos que tener una forma de recuperarnos del mismo para que el programa no termine con excepcin.Lo que deberamos hacer en aquellos lugares en donde sabemos qu hacer ante un problema (que idealmente son muy pocos) es atrapar la excepcin que caus el problema y evaluar un determinado cdigo para seguir adelante de forma correcta. Para eso primero tenemos que saber qu parte del cdigo a ejecutar es el que podra terminar en excepcin, luego qu tipo de error queremos tratar y finalmente qu se debera hacer al respecto.El siguiente cdigo va a pedirle a pepita que vuele, que puede romperse y supongamos que la forma de reaccionar ante alguna excepcin segn el requerimiento sea darle de comer para que no se muera:try { pepita.vola(100)} catch e : Exception { pepita.come(50)}Un problema que tiene esta solucin es que para cualquier problema se le va a dar de comer a pepita, si la energa de pepita no estuviera inicializada y el error surge de intentar tratar a la nada como un nmero, o si pepita no entiende el mensaje para volar, tambin resolvera el problema con el bloque que le da de comer en vez de romperse, de modo que sepamos que el problema existe. Eso lgicamente no es correcto.Considerando que el mensaje self.error(descripcion) lanza una excepcin ms particular que Exception, una primer mejora que se puede hacer es acotar ante qu tipo de error queremos darle de comer a pepita:try { pepita.vola(100)} catch e : DomainException { pepita.come(50)}Eso va a evitar que nos recuperemos incorrectamente de errores como ser mensajes no entendidos, ya que no son de tipo DomainException, sin embargo sera interesante poder refinarlo un poco ms, para tener la certeza de que slo vamos a estar manejando con este mecanismo las excepciones que surjan por tener energa insuficiente.Ac entra en juego nuevamente la jerarqua de clases de excepcin. En vez de simplemente usar self.error(descripcion), podramos tener clases propias que hereden de la clase de excepcin ms apropiada (en este caso DomainException podra tener sentido):class EnergiaInsuficienteException inherits DomainException {}y luego hacer algo as en el mtodo vola(kms) de pepita: throw new EnergiaInsuficienteException(message = "Energa insuficiente para volar los kilmetros requeridos").Eso permite atrapar slo las excepciones que me interesan y dejar pasar las que no s cmo manejar para que alguien ms se ocupe. Por ejemplo:try { pepita.vola(100)} catch e:EnergiaInsuficienteException { pepita.come(50)}Tambin, si estamos testeando podemos verificar que el resultado de ejecutar algo sea no poder volar:assert.throwsExceptionWithType(new EnergiaInsuficienteException(), {pepita.vola(100)})Al usar throwsExceptionWithType el test va a dar verde exclusivamente cuando el bloque al ejecutarse lanza una excepcion cuya clase sea EnergiaInsuficienteException o alguna subclase de la misma. Si el error que lanza ejecutar ese bloque es por ejemplo que un objeto no entendi un mensaje como se explic antes, el test no va a dar verde, y es exactamente lo que necesitamos.Estrategias para manejar excepciones La forma por excelencia de lidiar con una excepcin es no hacer nada!!. La mayora de las veces no tenemos la capacidad de recuperarnos del problema en el mismo lugar donde se produce, lo ms sano es dejarla burbujear hasta el punto en donde s haya algo para hacer al respecto. Atraparla, hacer algo y continuar con el flujo normal de ejecucin. Atraparla, hacer algo y volver a lanzar la misma excepcin. Eso se puede hacer volviendo a usar throw usando la excepcion atrapada en el bloque que maneja el problema. Atraparla y lanzar otra ms adecuada agregando ms informacin del problema. Las excepciones adems de un mensaje descriptivo pueden tener asociada una causa que es otra excepcin y sirve justamente para los casos en los cuales se usa esta estrategia. Si vemos stacktrace completo de una excepcin que tiene una instancia de otra excepcin como causa, podremos notar que se incluye la informacin de ambas excepciones, sin perder informacin por el camino.Donde es comn atrapar excepciones?Lo ms usual es que las excepciones no se atrapen en el cdigo de nuestros objetos de dominio, sino mucho ms lejos, en unos pocos lugares puntuales. Por ejemplo, si tenemos un sistema con una interfaz grfica que es la que el usuario final usa para interactual, vamos a querer que en esa interfaz se muestre un mensaje razonable para que el usuario vea. Por ejemplo, si el problema est relacionado con alguna accin incorrecta por parte del usuario, lo ideal sera comunicrsela de modo que pueda entender el problema y corregirlo; si en cambio es un problema inesperado sobre el cual el usuario no puede hacer nada (un problema del programa en s, no del uso), se le podra mostrar otro tipo de mensaje para que sepa que hubo un problema y tambin informar del problema a los desarrolladores para que puedan analizarlo y trabajar sobre la causa.En las herramientas de testeo que usan nuestro cdigo tambin de seguro se estn atrapando las excepciones que se lancen al ejecutar nuestra lgica, lo cual lleva a que se reporte adecuadamente si las pruebas pasaron, si fall una asercin o si hubo un error inesperado, y la informacin de esas excepciones que se atraparon debera poder ser vista por quien corre las pruebas.Eso no quiere decir que nunca se atrapen excepciones dentro del modelo, sin embargo hay que entender que no es tan comn, y es importante no abusar de estas herramientas, ya que podran traer ms problemas que soluciones." + +} , + +{ + +"title" : "Expresiones lambda", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/expresiones-lambda.html", +"date" : "", +"content" : "Son funciones annimas. Por ej., una funcin annima que toma solo un nmero como argumento y produce el resultado x + x se puede definir como:xx+xEn Haskell: se escribe &#92; y se escribe -&gt;;Esa definicin no es ms que una funcin doble, por eso podemos escribirdoble=&#92;x-&gt;x+xA pesar de no tener nombre, pueden usarse como cualquier otra funcin:&gt;(&#92;x-&gt;x+x)24Una expresin lambda puede recibir ms de 1 parmetro separndolos por espacio dentro de la expresin--cuentaLocaesunafuncinquerecibe3parmetroscuentaLoca=(&#92;xyz-&gt;x*2-y+10*z)La gracia de poder definir funciones annimas es que nos permite armar fcilmente una funcin para usar en el momento. En general cuando ms jugo se les saca a las expresiones lambda es para usar funciones de orden superior, sin embargo pueden usarse en cualquier lugar donde se espere una funcin. Como las expresiones lambda son funciones, las mismas pueden combinarse con otras funciones usando Composicin.Una de las ventajas que tienen las lambdas por sobre otros mecanismos de crear nuevas funciones cuando las necesito sin tener que definirlas en otro lado, es que los parmetros tienen un nombre y puedo usar ese mismo parmetro tantas veces como quiera dentro de la definicin. Si por ejemplo quisiramos saber si la edad de una persona es menor a 20 o mayor a 60, podra resolverse de la siguiente forma:&gt;((&#92;e-&gt;e&lt;20||e&gt;60).edad)personaAlgo importante a tener en cuenta es que si no le damos un nombre a nuestras funciones podramos perder abstracciones tiles que podran luego ser utilizadas en otros puntos de nuestro programa, por lo tanto es importante ser criteriosos respecto a si es una buena idea buscar un nombre para nuestra funcin.Por lo general, si tengo una forma sencilla de nombrar una determinada lgica que forma parte de una funcin ms grande, lo ms probable es que no quiera definir ese pedacito de lgica usando una lambda, sino con una funcin que se llame como la idea que tenemos en la cabeza. Si no hay un nombre claro asociado a ese pedacito de lgica, lo ms probable es que no sea un concepto del dominio que merezca la pena modelar como algo aparte.Lambdas y Pattern MatchingAlgo interesante que se puede hacer con las expresiones lambda es descomponer sus parmetros usando pattern matching como cuando definimos funciones normales. Supongamos que dado un alumno modelado con una tupla de tipo (String, [Int]) quiero obtener la primer nota que se sac, se podra resolver de la siguiente forma:&gt;(&#92;(_,(nota:_))-&gt;nota)alumnoAl usar pattern matching hay que tener en cuenta que si el parmetro que le llega a la lambda no matchea (por ejemplo si en este caso el alumno no tiene notas), al ejecutarse va a tirar un error indicando que los patrones usados no fueron exhaustivos, lo que significa que la funcin tiene un dominio acotado, posiblemente ms de lo que queramos.Para este ejemplo no nos interesa contemplar a los alumnos sin notas porque no tenemos una buena respuesta para dar en ese escenario, con lo cual la solucin sera correcta.Uso de lambdas en vez de aplicacin parcialUno de los conceptos fuertes que existen en el paradigma funcional es el de Aplicacin Parcial, que nos permite crear una funcin nueva a partir de otra existente cuando nos hace falta para combinarla con otras funciones mediante composicin o simplemente pasarla por parmetro para que otra funcin la evale cuando corresponda.Siempre que usamos aplicacin parcial podemos tambin usar una lambda, por ejemplo:&gt;map(+1)[1..10]Tiene el mismo resultado que:&gt;map(&#92;n-&gt;n+1)[1..10]En casos como este, el uso de aplicacin parcial es ms interesante que el uso de la expresin lambda. No slo hacemos lo mismo con menos cdigo sino que demostramos un mayor entendimiento de los conceptos ms fuertes del paradigma.Sin embargo hay casos en los cuales no podemos resolver el problema aplicando parcialmente (ver: Puedo aplicar parcialmente el segundo parmetro en vez del primero?) la funcin que queremos usar que s justifican el uso de una expresin lambda." + +} , + +{ + +"title" : "Expresividad", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/expresividad.html", +"date" : "", +"content" : "DefinicinLa expresividad puede definirse informalmente con la heurstica el nivel de lindez del cdigo. En otras palabras, escribir un cdigo expresivo es poner atencin a las cuestiones que hacen que este cdigo fuente sea ms fcil de entender por una persona.Por qu por una persona y no por una pc?Para responder esa pregunta comparemos estos dos cdigos en Pascal:FunctionQuieroMoverElBote(a:ArrayofInteger,c:Integer):Real;Varb:Integer;d:Real;e:Integer;Begin Forb:=1tocdo Begin e:=e+a[b]; End; d:=e/c; QuieroMoverElBote:=d;End.FunctionPromedio(numeros:ArrayofInteger,cantidad:Integer):Real;Var i:Integer;sumatoria:Integer;Begin Fori:=1tocantidaddo Begin sumatoria:=sumatoria+numeros[i]; End; Promedio:=sumatoria/cantidad;End.En la segunda implementacin puede verse con claridad el objetivo de este programa, mientras que en el primero est escondido. Sin embargo, la computadora ejecutando este cdigo produce exactamente el mismo resultado con cualquiera de los dos programas. La diferencia est en el programador que lee un programa el otro.Es por eso que muchas veces se suele considerar a la Expresividad como algo subjetivo. Sin embargo, en lneas generales, hay formas de alcanzar la expresividad.MotivacinEn general, las tcnicas que favorecen la mejor comprensin del cdigo fuente (por un programador) son tcnicas que no cambian en funcionamiento del programa. Entonces, si en ltima instancia el programa hace lo que corresponde, Por qu habramos de consumir tiempo escribiendo cdigo expresivo?En la industria actual de software (de hecho, en cualquier ambiente en el que sea necesaria la produccin de software) existen ciertas caractersticas / problemas a resolver, consecuencia de que los programas son cada vez ms grandes, complejos, y cambiantes. En consecuencia: Se espera que sean flexibles (que puedan cambiarse fcilmente) Se espera que fallen poco (con lo cual es importantsimo encontrar y corregir errores tempranamente). El desarrollo dura mucho tiempo. (Meses, aos) El equipo de desarrollo es amplio. (Mucha gente escribiendo el mismo programa).En consecuencia, la labor de un programador es en su amplia mayora, leer y corregir cdigo existente (propio de otro) y en menor medida producir cdigo nuevo.Es por todo esto que el cdigo fuente no puede ser exclusivamente escrito para la computadora. El ms importante destino del cdigo son las propias personas. Es por eso que no se puede descuidar la expresividad: es una de las varias formas de hacer la vida del programador ms sencilla, para que pueda abordar la construccin de sistemas como el mencionado.Cmo lograr la expresividadHay varias formas de lograr expresividad, entre las que se destacan: Usar buenos nombres Usar buenas abstracciones en general (y en particular, la Declaratividad). Identar correctamente el cdigo.Buenos NombresBuen resumen (en ingls) http://c2.com/cgi/wiki?GoodVariableNames Un buen nombre debe decir exactamente cul es el propsito de la variable / procedimiento / mtodo. Por ejemplo, la funcin de arriba pas de llamarse QuieroMoverElBote a Promedio, y el array de llamarse a a llamarse numeros. Ser descriptivo. Por ejemplo, no tener miedo de escribir nombres largos. cantAlumnosAprobados es mejor que aprobados. Ser claro y simple. Por ejemplo, se pueden usar abreviaciones claras (como cant en vez de cantidad). Aunque las abreviaciones pueden resultar a veces dainas: alumnosAprobados es mejor que alsAp Respetar las convenciones es buena idea. Por ejemplo, el cdigo escrito en lenguaje Python separa las palabras dentro de un nombre as: esto_es_una_variable, mientras que en Smalltalk la convencin es as: estoEsUnaVariable. Dar idea (no muy especfica) del tipo ayuda tambin a la expresividad. Por ejemplo, en el array del ejemplo de arriba hay una variable que se llama numeros. Esto da a entender rpidamente que son muchos, y que son de algn tipo numrico, exactamente cul no es importante para entender qu hace. Ejemplos de malos nombres son numero, ints arrayNumeros. Tampoco es buena idea llamar a la funcin realPromedio, porque ensucia la legibilidad. Se sobreentiende que un promedio es de un tipo real flotante. El tiempo que uno gasta en encontrar/pensar un buen nombre, es tiempo bien aprovechado.Declaratividad Ver Declaratividad vs. ExpresividadIdentacinIdentar el cdigo (separar con espacios) es una buena manera de hacer que el cdigo sea legible. Nuevamente, no debe abusarse de sto, ni usarlo poco. Y respetar las convenciones del lenguaje es buena idea. En el ejemplo de arriba se ve claramente cmo la identacin ayuda a leer mejor el programa, y de paso se respeta la identacin sugerida de Pascal." + +} , + +{ + +"title" : "Articulo Destacado", +"category" : "", +"tags" : "", +"url" : "/wiki/internal/featured_article.html", +"date" : "", +"content" : "Articulo DestacadoTODO" + +} , + +{ + +"title" : "Fideos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/fideos.html", +"date" : "", +"content" : "Proporciones: 100gr harina 1 huevo" + +} , + +{ + +"title" : "Flattening vs linearization", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/flattening-vs-linearization.html", +"date" : "", +"content" : "Cuando el comportamiento de un objeto es separado en distintas abstracciones, es necesario definir cmo se resolver la tarea de encontrar el comportamiento definido (method lookup).Si las abstracciones son suficientemente dispares (sin comportamiento en comn), pueden pensarse como complementarias, y, en consecuencia, la manera en la que se desarrolle dicha bsqueda no impactar en el comportamiento resultante. Sin embargo, cuando las abstracciones son anlogas, o peor, contradictorias, el mecanismo que define el comportamiento final del objeto es un factor crtico.Todos los lenguajes que brindan dicha modularizacin de abstracciones ofrecen de una u otra manera un mecanismo de bsqueda de comportamiento, de donde se destacan dos visiones principales: linearizacin (o linearization) y el aplanado (flattening).La linearization es un mecanismo que define un orden para las abstracciones, priorizando unas sobre otras. A la hora de proveer un mtodo, aquella con mayor prioridad es la que lo otorga. Todo mecanismo de linearization define un Method Resolution Order (MRO). El caso ms comn es el de la herencia simple, en donde si un objeto recibe un mensaje, el mtodo que se ejecutar es el que est ms cercano avanzando hacia lo ms general en la jerarqua de herencia. Este mecanismo tambin es usado para la herencia mltiple y los Mixins.El flattening es un mecanismo que no prioriza abstracciones, sino que deja al usuario resolver las situaciones contradictorias o conflictos, mediante diferentes herramientas. Los Traits de Smalltalk se manejan con flattening, y la manera de solucionar conflictos se basa en el uso de operaciones para ajustar la composicin de traits a las necesidades de cada caso, siendo un mecanismo muy flexible y a la vez simple de entender. Respecto al method lookup, como este mecanismo aplana los mtodos definidos en la clase usuaria, encontrar el mtodo correspondiente a un mensaje provisto por la otra entidad es lo mismo que encontrar el mtodo para un mensaje propio." + +} , + +{ + +"title" : "Fold", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/fold.html", +"date" : "", +"content" : "Existe una familia de funciones en Haskell para modelar un algoritmo que permite procesar una estructura de datos para construir un valor, a esta idea le decimos foldear (derivado del ingls, to fold) o reducir.Cmo sumo los elementos de una lista? Cmo multiplico los elementos de una lista? Cmo concateno una lista de palabras?sum[]=0sum(x:xs)=x+sumxsprod[]=1prod(x:xs)=x*prodxsconcatenar[]=[]concatenar(x:xs)=x++concatenarxsO bien si usamos los operadores de forma infijasum[]=0sum(x:xs)=(+)x(sumxs)prod[]=1prod(x:xs)=(*)x(prodxs)concatenar[]=[]concatenar(x:xs)=(++)x(concatenarxs)Si vemos las diferencias entre estas funciones notamos que slo cambia la operacin a realizar y el valor inicial, por ende si queremos hacer una funcin que nos generalice el algoritmo tenemos que recibirlos como parmetro.En trminos generales cmo la paso a una funcin de orden superior? Necesitamos: una funcin que opera con dos parmetros un valor inicial una listafoldr::(a-&gt;b-&gt;b)-&gt;b-&gt;[a]-&gt;bCaso base: si la lista es vaca, devuelvo el valor inicial.foldrfvalorInicial[]=valorInicialSi la lista no es vaca, qu voy a tener que hacer? A partir de alguna de las funciones podemos trasladar:concatenar(x:xs)=(++)x(concatenarxs)foldrfvalorInicial(x:xs)=fx(foldrfvalorInicialxs)Sumando con foldrsum=foldr(+)0Para sumar una lista hay que aplicar la suma elemento por elemento arrancando de 0. Como es difcil de asimilar de golpe, vamos a hacer el seguimiento de un caso:&gt;sum[2,3,5]=foldr(+)[2,3,5]=(+2)(foldr(+)0[3,5])=(+2)((+3)(foldr(+)0[5]))=(+2)((+3)((+5)(foldr(+)0[])))=(+2)((+3)((+5)0))&lt;-casobase=(+2)((+35))=(+2)8=10Si revisan el Prelude, van a encontrar otra funcin similar:foldlfz[]=zfoldlfz(x:xs)=foldlf(fzx)xsfoldl vs foldrCul es la diferencia? Revisemos los tipos:foldl::(a-&gt;b-&gt;a)-&gt;a-&gt;[b]-&gt;afoldr::(a-&gt;b-&gt;b)-&gt;b-&gt;[a]-&gt;bFoldr trabaja asociando a derecha la funcin f, mientras que foldl trabaja asociando a izquierda la funcin f. El seguimiento de la sumatoria definida en base a foldl puede ayudar a entender cmo realiza la operatoria:sum=foldl(+)0&gt;sum[2,3,5]=foldl(+)0[2,3,5]=foldl(+)((+)02)[3,5]=foldl(+)((+)23)[5]=foldl(+)((+)55)[]=foldl(+)10[]=10&lt;-casobaseY aqu vemos que el valor inicial del caso base es en realidad el resultado final. Para comparar la forma de trabajar de las dos funciones pueden realizar consultas de este estilo en su intrprete de Haskell (show es una funcin que retorna la representacin de el valor recibido como string):&gt;foldr(&#92;xy-&gt;concat["(",x,"+",y,")"])"0"(mapshow[1..13])"(1+(2+(3+(4+(5+(6+(7+(8+(9+(10+(11+(12+(13+0)))))))))))))"&gt;foldl(&#92;xy-&gt;concat["(",x,"+",y,")"])"0"(mapshow[1..13])"(((((((((((((0+1)+2)+3)+4)+5)+6)+7)+8)+9)+10)+11)+12)+13)"Otras variantes de fold son foldl1 y foldr1 que trabajan de forma anloga a las anteriores slo que toman como valor inicial al primer elemento de la lista. Eso es til para los casos en los que la lista no debera estar vaca y/o no hay un valor adecuado para parametrizar. Veamos un ejemplo:maximum'=foldr1max" + +} , + +{ + +"title" : "Formato de un paper", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/formato-de-un-paper.html", +"date" : "", +"content" : "No todas las secciones son necesarias, pueden haber otras secciones o con otros nombres. Este solo es un template de gua.TtuloHay que elegir un buen ttulo :)AbstractEl abstract no es otra cosa que un resumen de todo el paper. Debera contener aproximadamente una oracin para cada uno de los siguientes temas: contexto problema porque es un problema solucion que se presenta como lo que presentamos soluciona el problema quizas algun ejemploDespus de leer el abstract, el lector debera saber de qu se trata el paper a groso modo, y poder decidir si quiere seguir leyndolo o no, si le sirve o noIntroductionLa introduccin le muestra al lector que hicimos la tarea. S, que sabemos de qu estamos hablando, conocemos los problemas, conocemos lo que otra gente hizo. Aca se explica mucho del contexto en el que nos paramos y brevemente los otros puntos, ya que van a ser mejor explicados en las secciones que siguen. Context: contar el contexto del problema, qu tecnologa, qu ambiente. es relacionado a web apps? A lenguajes con chequeo esttico de tipos? Lenguajes con herencia mltiple? Problems: contar brevemente los problemas que se quieren solucionar Current Solutions: contar brevemente las soluciones existentes que existen que atacan el problema Contributions: que agregamos nosotros a la investigacin en el tema Outline: contar de qu se tratan las secciones que siguen. Es el tpico In section 2 we present In section 3 we show our implementation of blehProblems Constraints: Sobre qu limitaciones trabajamos? Ambientes con mucha seguridad? Sin conexin de red? Vms restrictivas?Luego enumeramos los problemas actuales que vamos a encarar: Problem1 Problem2 Your solution in a nutshell: contamos nuestra solucin muy brevemente, contando en muy pocas lineas qu problemas resolvemos. Estamos invitando a que nos sigan a la prxima seccin.My SolutionContamos la solucin. Hice X, Y y Z, que solucionan los problemas A, B y C, as y as. No comparamos con otra gente ni otras soluciones. Esta seccin es toda nuestra.DiscussionLa discusin es donde: nuestra solucin se compara con las existentes abrimos la puerta a lneas que no se llegaron a explorar aca, que podran encararse en el futuro.ImplementationAca podemos hablar de nuestra implementacin en particular. Es la parte menos de investigacin(?).EvaluationQu tan buena es nuestra implementacin y como soluciona los problemas que enumeramos. Aca podemos poner benchmarks, mtricas, etc.Related workAca normalmente se hablar de gente trabajando en cosas parecidas, no necesariamente sobre el mismo campo, o buscando la misma solucin. Es bastante similar a Discussion, y por eso ambas secciones pueden ser una sola.ConclusionEs un resumen post lectura, o sea, el lector ya tiene nuestro laburo en la cabeza: Nuestra solucin X pareciera ser una buena solucin al problema Y, aunque no tanto para el problema Z. Queda por explorar el camino J, que encar inicialmente el autor Fulanito[cita]" + +} , + +{ + +"title" : "Frases teadepeanas", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/frases-teadepeanas.html", +"date" : "", +"content" : " The way to keep designers sharp and honest is to make them eat their own dog food. Michi Henning" + +} , + +{ + +"title" : "Funciones por partes", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/funciones-por-partes.html", +"date" : "", +"content" : "Concepto MatemticoLas funciones partidas definidas por partes por trozos son funciones que para diferentes valores del dominio, tienen una definicin diferente. Por ejemplo, si tenemos que definir la funcin Mdulo, para ciertos valores del dominio la funcin ser f(x) = x y para otros valores ser f(x) = -xNotacin MatemticaCdigo en HaskellEn Haskell, las funciones partidas se escriben con Guardas, y se escribe la imagen de cada parte a la derecha del igual:fx|x&gt;=0=x|x&lt;0=-xLas funciones por partes no son la nica forma de tener diferentes definiciones para una funcin, existen casos en los cuales alcanza con el uso de pattern matching.Errores ComunesNo debemos confundir el uso de guardas (cuyo concepto se explic arriba) con las funciones que devuelven booleanos.Ejemplo 1Tomemos ste ejemplo: Cierta edad es adulta cuando es 18 msesAdultaedad|edad&gt;=18=True|otherwise=FalsePero esto es un uso incorrecto de las guardas! En otras palabras: Si una expresin es verdadera falsa por s sola, no se lo debo preguntar, tengo que devolver directamente eso.sta es la manera correcta de hacerlo:esAdultaedad=edad&gt;=18Ejemplo 2Representemos una funcin que me diga si alguien siempre dice la verdad, sabiendo que los nios y los borrachos siempre dicen la verdad sta es una manera de hacerlo, errnea:siempreDiceLaVerdadalguien|esNioalguien=True|esBorrachoalguien=True|otherwise=FalseSi bien sto funciona, es un mal uso de las funciones por partes, ya que no es cierto que esa funcin tenga diferentes partes. La definicin es lgica, y es una sola. Es un lgico:Cuando alguien dice la verdad? cuando es nio cuando es borrachoEsa es la definicin de la funcin. Recordemos que el logico se escribe as:Main&gt;(1&gt;34)||(even4)Truey el y lgico se escribe as:Main&gt;(1&gt;34)&amp;&amp;(even4)FalseEntonces, mi funcin se define sin guardas, de sta manera:siempreDiceLaVerdadalguien=esNioalguien||esBorrachoalguienEjemplo 3: No usar pattern matchingA veces, cuando estamos aprendiendo guardas, nos olvidamos que poseemos Pattern Matching en Haskell.En otras palabras, podramos tener una funcin as:ivaParaactividad|actividad=="cultural"=0.0|actividad=="alimentaria"=10.5|otherwise=21.0Cuando en realidad, con Pattern Matching, podra quedar ms declarativo:ivaPara"cultural"=0.0ivaPara"alimentaria"=10.5ivaPara_=21.0Otro ejemplo de lo mismo:longitudlista|nulllista=0|otherwise=1+longitud(taillista)Cuando quedara ms declarativo:longitud[]=0longitud(_:resto)=1+longitudrestoEjemplo 4: Hacer la guarda antes de tiempo (Repeticin de cdigo)Cuando se repite cdigo a ambos lados de la guarda, sto es un problema:fa|a&lt;3=2+ 5 * g a|otherwise=1+ 5 * g aQue puede arreglarse as:f a = fAux a + 5 * g afAuxa|a&lt;3=2|otherwise=1Nahuel Palumbo (El Rasta) denomin este tipo de repeticin Hacer el if antes de tiempo, y sucede tambin en otros paradigmas y lenguajes.Ejemplo 5: Repeticin de cdigo ms rebuscadaTambin puede pasar que se repita cdigo entre las guardas de esta manera:Se quiere saber el precio del boleto a partir de la cantidad de kms que voy a recorrer. Se sabe que a partir de 4 km, el clculo del boleto es el clculo mximo ($2 + $0.1 x cantidad de kms), mientras que hasta los 4km, el clculo es el 110% del clculo mximoSe propuso esta solucin:precioBoletokms|kms&gt;=4=2 + 0.1 * kms|otherwise=110/100*(2 + 0.1 * kms)Pero arriba y abajo se repite 2 + 0.1 * kms. En este caso, se arregla con la forma ms comn de corregir la repeticin de lgica: delegando en ambos casos en la misma funcin.En otras palabras, si yo tengo:maximokms=2+0.1*kmsEntonces esa lgica est ahora en un slo lugar, que puedo llamar desde donde necesite:--Solucinfinalcorrecta:precioBoletokms|kms&gt;=4=maximo kms|otherwise=110/100*(maximo kms)Hay otras formas mejores y peores de evitar ste tipo de repeticiones, pero sta forma (delegando) es bastante buena y sirve en muchos casos." + +} , + +{ + +"title" : "Function object", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/function-object.html", +"date" : "", +"content" : "Entendemos por Function Object a un patrn funcional aplicado a objetos que consiste en cosificar el envo de mensajes, para poder resolver problemas empleando orden superior y aplicacin parcial de forma similar a como lo haramos en el paradigma funcional.El problemaEn el paradigma de objetos los mensajes no son objetos, y por tanto no tenemos forma de hablar contra los mensajes, mas all de las capacidades reflexivas de algunos lenguajes. Dicho de otra forma los mensajes no son valores, no son cosas.Esto nos restringe en que no tenemos mucho control sobre estos envios: por ejemplo, no tenemos forma nativa de enviar mensajes parciales o de pasar el envo de un mensaje por parmetro.Por ejemplo, en Haskell, uno puede escribir los siguiente:map(1+)[1,2,3]dado que las funciones estn currificadas (lo cual se aprecia en la expresin 1+, donde se aplica parcialmente + con el valor 1, devolviendo otra funcin), y son valores (1+, es un valor que puede ser pasado como argumento a map)Si el envo de mensajes en Smalltalk fuera un valor, uno bien podra escribir lo siguiente:#(123)collect:(1+)(omitiendo el argumento del mensaje +)o#(123)collect:(+1)(omitiendo el receptor del mensaje + 1)Para suplir estas limitaciones, la estrategia usada en objetos consiste justamente en cosificar el envo de mensajes, construyendo objetos que lo modelen. En lenguajes como Smalltalk, tenemos una forma nativa de construir tales objetos: los bloques de cdigo.Por ejemplo, en Smalltalk, la funcionalidad anterior se implementa de la siguiente forma:#(123)collect:[:x|x+1]Lo cual es anlogo al siguiente cdigo Haskell:map(&#92;x-&gt;x+1)[1,2,3]En el sentido de que explcitamente construye un valor que modela una computacin, que los argumentos de la misma son explcitos y estn etiquetados. Pero con la diferencia de que en Haskell, el uso de una lambda es redundante, mientras que en Smalltalk es necesario.Justamente por su semejanza con la definicin de una funcin annima, a este patrn se lo conoce como Function Object: un objeto que entiende en su versin ms simple un nico mensaje (llamado tpicamente apply, value, call, eval, etc) y cosifica un envio de mensajes.Estos objetos pueden entender opcionalmente otros mensajes que permitan implementar la nocin de aplicacin parcial y/o currificacin, y que implementen operaciones tpicas sobre funciones como, por ejemplo, la composicin.En lenguajes como Java, dnde no tenemos una sintaxis especfica para instanciar estos bloques de cdigo, tenemos que recurrir a la definicin e instanciacin explcita de clases, tpicamente definiendo una o varias interfaces que representen a las funciones de diferentes aridades, e implementdolas e instanciandolas conjuntamente, mediante el uso de clases annimas.As por ejemplo, es comn encontrar encontrar cdigo que emplea bibliotecas (no estndares) de colecciones de la siguiente forma:javaCollections.map(Arrays.asList(1,2,3),newFunction&lt;Integer, Integer&gt;(){publicIntegerapply(Integerx){returnx+1;}});`Lo cual es evidentemente mas verborrgico y tiene mucha mas redundancia que las soluciones anteriores, pero igualmente cumple su cometido.Function Object y Orden SuperiorFunction Object y ClosureFunction Object, Strategy y Command" + +} , + +{ + +"title" : "Garbage collector", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/garbage-collector.html", +"date" : "", +"content" : "El garbage collector es un mecanismo que provee la Mquina Virtual para manejar la memoria de forma transparente para el desarrollador. Cuando un objeto ya no es referenciado por ningn otro, deja de ser til porque nadie puede mandarle mensajes. Si ya no es til, est ocupando espacio innecesariamente, con lo cual el garbage collector se encarga de liberar ese espacio sin afectar al sistema.Al tener un garbage collector podemos evitarnos los problemas asociados al manejo manual de memoria que ocurren comunmente, por ejemplo, en lenguajes como C como liberar ms de una vez la misma posicin de memoria, leaks de memoria, etc. A su vez nos permite concentrarnos en los que nuestro programa debe hacer con un grado de abstraccin ms alto.Hay garbage collectors con diferentes estrategias, la ms utilizada es la generacional que se basa en el hecho de que los objetos con mayor propensin a no ser necesitados nuevamente son los ms nuevos (por ejemplo, el resultado de un clculo que se usa en el momento y no se necesita ms), a partir de esta idea es posible optimizar el algoritmo de recoleccin. Resolver esta problemtica a mano para cada programa no slo desva nuestra atencin del objetivo, adems que sea igualmente o ms eficiente que un algoritmo genrico y ampliamente probado es muy poco probable.Para la gente curiosa, ac hay un artculo simptico que muestra grficamente distintos algoritmos de recoleccin: Visualizing Garbage Collection Algorithms" + +} , + +{ + +"title" : "Git un versionador distribuido", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/git--un-versionador-distribuido.html", +"date" : "", +"content" : "Distribuido Se dice de git que es un sistema de control de versiones distribuido. Que sea distribuido implica que van a existir al menos tantos repositorios como personas trabajando en el proyecto, a lo que se le pueden sumar uno o ms repositorios que se usen como intermediarios para compartir cambios entre las distintas personas. Un lugar prctico para hostear repositorios pblicos puede ser [https://github.com/ gtihub] RepositorioPor repositorio se entiende el lugar donde se van guardando todas las versiones de un proyecto o de cada una de las cosas que forman parte de l.En el mundo git en vez de pensar en que cada archivo es una parte que va cambiando de versiones prefirieron pensar en que es todo el proyecto el que se va versionando entonces cada vez que se modifica una parte en realidad se est modificando todo el proyecto.Un proyecto no es otra cosa que una arbol de directorios y archivos donde la raz del arbol es la carpeta raz del proyecto. Este Arbol es lo que va cambiando a medida que avanza el proyecto.La forma en que git elige modelar el proyecto es como un arbol por lo que en el interior de un repositorio git van a existir tantos rboles como versiones distintas existan del proyecto. Estos rboles van a formar parte de un DAG?DAG lo qu?Veamos primero un dibujito:DAG es la forma cheta de decir grafo dirigido acclico. O sea un dibujo con circulitos (nodos) y flechitas (vrtices) que unen los circulitos sin que se pueda llegar al mismo crculo saltando de crculo en crculo siguiendo las flechitas que los unen.Un rbol es de por s un DAG por lo que no tiene problemas en ser parte de un DAG ms grande que lo contiene.Cada uno de los crculos representa un objeto almacenado en el repositorio (nodos en el DAG). Los rectngulos son referencias que sirven como punto de entrada a los objetos que viven en el repositorio, podran considerarse parte del DAG pero estn representados como rectngulos para diferenciar las referencias de los objetos almacenados.Los distintos colores de los circulos representan cada uno de los 4 tipos de objetos que existen: blob. Representa un archivo en el proyecto. tree. Representa una carpeta en el proyecto, el primero corresponde al directorio raiz del proyecto o el mismsimo proyecto. commit. La forma de agregar objetos al repositorio es con la opercin commit. Esto agrega un objeto commit que tiene un vrtice hacia un tree que representa al directorio raz del proyecto. El sub-grafo que comienza en este tree representa el estado de todo el proyecto tras la ejecucin del commit. En el dibujo se ve que los subgrafos que parten de cada commit comparten un objeto blob, esto significa que el commit B no modific el archivo que agreg el commit A.El commit tambin conoce a su padre que es el commit que lo antecede, entonces los cambios que aplica un commit al proyecto son las diferencias entre el rbol al que apunta y el rbol al que apunta su padre. Cuando se ejecuta la operacin merge se qenera un commit que tiene al menos dos padres entonces los cambios que aporta este commit depende de contra cual de sus padres se lo compare. tag. La operacin tag genera un objeto tag en el repositorio y una referencia de tipo tag para accederlo.Un tag conoce un commit y a partir de este el estado del proyecto para ese commit. En su cuerpo tambin uncluye un ttulo un comentario y opcionalmente se le puede agregar una firma gpg. Todos los objetos (crculos en el dibujo) tiene un nombre bastante feo para identificarlos (algo as como 8357799df0b47164c9726be6610ea1b7ed41ff32), este nombre es el resultado de aplicar un funcin de hash (SHA1) al objeto.Referencias: Las referencias son los rectngulos en el dibujo, son simplemente puntos de entrada a los objetos almacenados en el repositorio. Referencia de tipo tag (amarillo en el dibujo) apunta a un objeto de tipo tag y es inmutable, o ms o menos inmutable. Referencia de tipo branch (verde en el dibujo) apunta a un ojeto commit, es mutable y al commit al que apunta es al * ltimo que se agreg para ese branch. Referencia de tipo branch remoto (gris en el dibujo) es muy parecida a un branch slo que se usa para seguir el estado de un branch en otro repositorio (recuerden que esto era distribuido). La del dibujo (origin/master) significa que sigue un branch llamdo master en un repositorio llamado origin. El nombre del repositorio es un shortcut de la url completa. HEAD esta referencia la usa git para saber que commit ser el padre del prximo commit, normalemnte apunta indirectamente a un commit a travez de un branch. Si almomento de ejecutar la opercin commit el HEAD apunta a un branch el branch se actualiza para apuntar al nuevo commit.Todo muy lindo pero cmo lo uso?Bueno primero lo tendras que tener instaldo. Eso se explica ac. Ahora que git ya est git intalado y configurado podemos ver un ejemplo partiendo de un proyecto nuevo.En la consola (git bash si ests en windows)$ mkdir ~/prueba $ cd ~/prueba $ git init Lo que estamos haciendo es comenzar un proyecto cuya carpeta raz ser ~/prueba, y en esa carpeta inicializamos un repositorio git para mantener las versiones de nuestro proyecto de prueba. El repositorio est en una carpeta llamada .git adentro de la carpeta raz del proyecto. La carpeta ~/prueba con todo su contenido menos la carpeta .git es lo que git llama working tree, algo similar a la working copy de svn.Git lo llama working tree porque un directorio en el file system que estemos usando es tambin un rbol y como git entiende los proyectos como rboles dice que la carpeta donde editamos los archivos del proyecto no es otra cosa que el rbol de trabajo.El repositorio no tiene todava ningn objeto almacenado (crculos del dibujo) pero s, tiene la referencia HEAD que apunta a ref/heads/master esto siginifica que apunta a un branch llamado master, el nombre master es el que se les ocurrio a los amigos de git para ponerle al branch principal, algo as como el trunk del svn. Un branch no es otra cosa que una referencia a un commit, pero como todava no existe ningn commit tampoco existe el branch master. La referencia HEAD sirve para que git sepa en que branch estamos trabajando actualmente, lo que significa que al hacer el prximo commit actualizar el branch apuntado por HEAD. En este caso que todava no se hizo ningn commit el branch master se crear con el primer commit.Vamos a crear nuestro primer commit$cd~/prueba#carpetarazdelproyecto$touchunTexto.txt#creounarchivo$gitaddunTexto.txt#agregoelarchivoalindexdegit$gitcommit-m"primercommit"#ejecutolaoperacincommitpasndoleelcomentario"primercommit"Basicamente la forma de trabajo es:Modifico el contenido del working tree (agrego y modifico archivos) Agrego alguno o todos los cambios al index (git add) Ejecuto un commit (git commit) Los cambios que aporta el commit es todo los que est en el index. Y qu es el index? Es un lugar donde voy acomodando los cambios que van a entrar en el prximo commit. Tambin llamado staging, pero en casi toda la documentacin de git aparece como index.como qued el grafo de nuestro repo:" + +} , + +{ + +"title" : "Introducción a Gradle", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/gradle.html", +"date" : "", +"content" : "IntroduccinGradle es una herramienta que ayuda a desarrollar un proyecto basado en el entorno de una JDK (Java, Kotlin, Xtend, Scala, Groovy, etc.) y que cumple con las siguientes funciones principales que vamos a explicar en las siguientes secciones: Reificacin del Proyecto Manejo de Dependencias a partir de repositorios locales y remotos Plugins y tareasReificacin de ProyectoJava no trabaja la idea de proyecto, no lo representa como concepto, y eso se traslada a todos los lenguajes basados en la JDK. Entonces, cada uno de los IDEs pensados para Java agregan su propia forma de definirlo: en Eclipse tenemos los archivos .classpath y .project en IntelliJ tenemos el directorio .idea en Visual Studio Code tenemos la carpeta .vscodeGradle permite trabajar en cualquiera de estos IDEs con su propio modelo de proyecto, que se guarda en el archivo build.gradle.kts en el caso de trabajar utilizando el lenguaje Kotlin o build.gradle a secas, cuando la configuracin se hace utilizando el lenguaje Groovy. A partir de ahora vamos a continuar la explicacin asumiendo que ests usando Gradle con Kotlin.Identificacin de un proyecto GradleTodo proyecto en Gradle tiene tres cosas que lo identifican: group: representa la organizacin autora/duea del artefacto. Por ejemplo, los proyectos de Algoritmos 2 suelen usar el groupId ar.edu.unsam.algo2. artifact: este campo define el nombre por el que se conoce al proyecto en s mismo. Algunos ejemplos: commons-collections, eg-seguros-kotlin, tp-futbol5-grupo01, etc. Aclaracin: los trminos componente y artefacto son sinnimos de proyecto. version: es el ltimo componente del rompecabezas, dado que groupId:artifactId denota un nico proyecto pero no alcanza para definir en qu versin del proyecto nos estamos parando. Se agrega entonces un nmero de versin para completar la informacin que Gradle necesita para generar una identificacin unvoca. Conviene seguir las reglas de versionado semntico, para liberar versiones productivas. A veces se suele acompaar de un sufijo RELEASE (para versiones estables) o SNAPSHOT (para versiones intermedias que pueden estar sujetas a cambios).Gradle tom de Maven, su antecesor directo, esta misma forma de identificar un proyecto. Vemos cmo se definen estos valores en el archivo build.gradle.kts:group = "ar.edu.unsam.algo2"version = "1.0-SNAPSHOT"El artifact se define en el archivo settings.gradle:rootProject.name = "eg-seguros-kotlin"Manejo de dependenciasRepositorios localesLas dependencias son tiles para poder acceder a cdigos escritos por otros (como la biblioteca Mockk o Apache Commons Collections). Cuando instalamos Gradle, se crea un repositorio local en una carpeta que por defecto suele ser HOME/.gradle, donde descargamos los componentes localmente una sola vez (muchos proyectos que usan la misma dependencia van a buscar el artefacto en ese mismo lugar). Podemos encontrar al componente cuyo identificador es io.kotest:kotest-assertions-core:5.1.0 en~/.gradle cachesmodules-2files-2.1 io.kotest kotest-assertions-core 4.4.3 (otra versin) 5.1.0 --&gt; dentro de esta carpeta estar el artefacto recordemos que el identificador de un componente se arma a partir del groupId + el artifactId + la versin en la cache de Gradle estn todos los componentes que descargamos localmente. Esto permite que cuando estemos trabajando en otro proyecto que comparta la misma dependencia no necesitemos ir a descargarla desde los repositorios. El comportamiento en una mquina Windows es exactamente igual, hay que explorar los directorios incluyendo los que son ocultos, y navegar a partir de la carpeta de usuario + &#92;.gradle.Repositorios remotosAhora bien, desde dnde descargamos las versiones 4.4.3 y 5.1.0 de io.kotest:kotest-assertions-core? Existen para eso repositorios remotos donde se publican artefactos: Maven Central, que es el repositorio principal donde estn subidos artefactos publicados con tecnologa Maven. Las dependencias ms importantes suelen estar en este repositorio y tens una pgina de bsqueda de artefactos, muy til cuando necesitamos bajarnos Mockito, Log4J, Kotest o cualquier otra dependencia. para los proyectos en Kotlin, otro repositorio importante es el de Google (tambin en Maven) ya que contiene componentes relacionados con el desarrollo de Android, entre otros. hay eventualmente otros repositorios remotos e incluso pods crear un servidor que funcione como repositorio de artefactos. Pods investigar Artifactory o JFrog, por el momento es suficiente con saber simplemente desde dnde estamos descargando nuestros componentes.En el archivo build.gradle.kts pods ver cmo se referencian los repositorios remotos:repositories { mavenCentral()}Definiendo dependencias en el proyectoLas dependencias se definen dentro de un tag dependencies:val kotestVersion = "5.1.0"dependencies { implementation(kotlin("stdlib")) testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion") testImplementation("io.kotest:kotest-assertions-core:$kotestVersion")}En este caso, estamos definiendo que nuestro proyecto tiene como pre-requisitos: la biblioteca estndar de Kotlin y los componentes kotest-runner-junit5 y kotest-assertions-core de io.kotest. La versin se define en una referencia val, el cdigo que escribimos para definir el archivo de configuracin es Kotlin.Una vez que hagamos un cambio en las dependencias, nos aparece el botn para sincronizar las definiciones del archivo con el IntelliJ, como vemos en este video:Al agregar una dependencia lo hacemos con el formato group:artifact:version y tambin definimos el tipo de alcance (scope), que puede ser implementation: el componente es necesario para hacer el build de nuestro proyecto. testImplementation: el componente es necesario para ejecutar los tests de nuestro proyecto. runtimeOnly: el componente se utiliza nicamente cuando tenemos levantada la aplicacin. Esta variante es til cuando trabajamos con objetos de resguardo (stubs o mocks) para ejecutar los tests (testImplementation) pero queremos tener un componente real que enva mails en la versin productiva (runtimeOnly). otras variantes pueden estudiarse leyendo la documentacin del plugin de Gradle para Java custom: para les interesades dejamos un artculo que explica cmo definir configuraciones propias extendiendo el modelo de GradleResumen general del manejo de dependencias de GradleFuente: https://docs.gradle.org/current/userguide/dependency_management.htmlAl hacer el build de nuestro proyecto si la versin de ese componente se encuentra descargado en nuestro repositorio local, se utiliza como dependencia vlida en caso contrario habr que buscar en los repositorios definidos en nuestro proyecto, como Maven Central, google, etc. en el orden en que fueron definidos si en ninguno de los repositorios fue posible encontrarlo, entonces recibiremos un mensaje de error cuando intentemos hacer build del proyecto:Dependencias transitivasUn detalle no menor de la resolucin de dependencias de Gradle es que tambin funciona para las dependencias transitivas.Por ejemplo: proyectoA &gt; proyectoB proyectoB &gt; proyectoC proyectoC &gt; proyectoD, proyectoE, proyectoFAl resolver las dependencias, el proyectoA necesitar descargar los componentes B, C, D, E y F. Incluso podramos requerir diferentes versiones de los mismos componentes.Noten que un proyecto comercial normal o mediano, puede incluir decenas y hasta cientos de dependencias. Esto se puede ver en IntelliJ desde la solapa Gradle, e inspeccionar compileClasspath: dependencias base para compilar los fuentes (que estn en src/main/kotlin) runtimeClasspath: dependencias que tendremos a la hora de ejecutar nuestra aplicacin en Kotlin, que incluye dependencias runtimeOnly. En Algoritmos 2 no vamos a levantar ninguna aplicacin, pero s ms adelante en Algoritmos 3. testCompileClasspath: dependencias que incluyen tanto fuentes como las marcadas como testImplementation, que sirven para ejecutar los tests.PluginsSi bien Gradle provee una plataforma para poder facilitar el manejo de dependencias, el build del proyecto y muchas otras actividades ms, quienes verdaderamente se encargan de esta tarea son los plugins, que terminan resolviendo cada una de estas cosas.Cada plugin permite definir qu elementos van a participar, extendiendo el modelo original de Gradle: por ejemplo el plugin de Kotlin configura la carpeta donde se ubican las clases principales en src/main/kotlin crear tareas, como la compilacin de todos los archivos Kotlin, o la ejecucin de los tests unitarios indicando cul es el framework, entre muchas otras cosas agregar configuraciones a nuestro proyecto, como repositorios adicionales donde ir a buscar dependencias, o definir una versin de la JDK por defecto.Pods ver en cualquiera de nuestros ejemplos qu contiene la seccin plugins del build.gradle.kts:plugins { kotlin("jvm") version "1.6.10" jacoco}En este ejemplo estamos utilizando una determinada versin del plugin de Kotlin para la JVM, para poder trabajar el proyecto adecuadamente en esa tecnologa y adems se agrega JaCoCo (Java Code Coverage), que agrega tareas para poder escribir reportes de porcentaje de cobertura de nuestros tests que luego sern utilizados por sitios que los publican, como Codecov o CoverallsPara ms informacin pueden consultar esta pgina.TareasUna tarea de Gradle no es otra cosa que una porcin de cdigo que se ejecuta en un determinado contexto. Por ejemplo, si escribimos en el archivo build.gradle.kts estas lneas de cdigo:tasks.register("saludar") { doLast { println("Hola, qu tal?") }}Podemos ejecutarlo desde el men de IntelliJ:Como se ve, es cdigo Kotlin lo que se ejecuta.En particular, el plugin Kotlin define la mayora de las tareas que vamos a utilizar: build construye el proyecto jar sirve para empaquetar las clases y generar un Java ARchive, un zip de archivos .class clean elimina carpetas temporales, algo til previo a un build test ejecuta las pruebas unitarias, algo que igualmente se hace tambin desde el IDE y muchas otras tareas ms que no hace falta conocer.Todas se pueden ejecutar de la misma manera que nuestra tarea custom saludar.Temas adicionalesGradle WrapperEn lugar de trabajar directamente con Gradle, cada proyecto en IntelliJ va a trabajar con un script genrico que constituye el Gradle Wrapper o wrapper a secas, que tiene algunas ventajas: no requiere instalacin local de Gradle, con lo cual es ms fcil estandarizar el proyecto y llevarlo a entornos de integracin continua permite trabajar cada proyecto con una versin particular de Gradle y actualizarla a futuro cuando lo deseemosLa pregunta que podemos hacernos es: esto cambia algo en mi forma de trabajar? No, en nada, pero es til entender por qu utilizamos gradlew como ejecutable por consola en lugar de gradle, y qu hace esta estructura dentro de nuestro proyecto:.gradlew.gradlew.batgradlewrappergradle-wrapper.jargradle-wrapper.properties # link a la versin de Gradle que estamos usandoPara ms informacin pueden ver esta pgina.Ejecutando gradle desde la consolaUna alternativa es trabajar directamente con Gradle desde la consola, algo que puede ser til para automatizar tareas, como cuando trabajemos con herramientas de integracin continua../gradlew clean buildEsto ejecuta varios plugins en forma sincronizada: por un lado la tarea clean borra el directorio build donde estarn los archivos compilados y luego compila los fuentes del proyecto, lo cual implica descargarse las dependencias, y compilar los archivos Kotlin a .class que una JRE pueda interpretarSi queremos ver el rbol de dependencias transitivas, podemos escribir./gradlew -q dependencies Documentacin oficialPara ms informacin recomendamos leer la documentacin oficial del proyecto Gradle tens tambin una pgina de tutoriales de Gradle un video bastante exhaustivo de personas que trabajan en Gradle: Getting Started with the Gradle DSL Kotlin de Paul Merlin &amp; Rodrigo de Oliveira. y un tutorial sobre Kotlin DSL de Anton ArhipovLinks relacionados Pgina principal de Algoritmos 2" + +} , + +{ + +"title" : "Groovy vs scala", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/groovy-vs-scala.html", +"date" : "", +"content" : "Advertencia: Esta articulo tiene una cuota importante de subjetividad; no es una comparativa exacta. As que tomalo con pinzas y record charlarlo con tu ayudante asignado.Para la materia diseo, ambas opciones son igualmente buenas. Te explico los pros (+), contras (-), y neutros (*) de cada una:Groovy: (+) Es sintcticamente el ms simple. Se parece mucho a Ruby o pseudocdigo. Usa pocas palabras reservadas y el cdigo es muy limpio. (+) El metamodelo es similar al de Java: tiene clases, mtodos, herencia, etc. Agrega mixins, pero tambin se codifican como clases. Tiene interfaces al estilo Java, pero no son necesarias. Esto te ayudar si quers usar el segundo cuatrimestre un fmwk de persistencia o presentacin para la JVM (como los dos para los que damos soporte) (+) Si vos y tu grupo quieren sacarle jugo, tiene cosas muy avanzadas y pods aplicar ms tcnicas de diseo. Por eso es que lo estamos usando para TADP (*) Tiene tipado dinmico e implcito (no escribs el tipo, los errores saltan en tiempo de ejecucin). Pods usar tambin tipado explcito si quers (ponerle tipo a las variables), pero en la mayora de los casos el chequeo de tipos seguir ocurriendo en tiempo de ejecucin, como en Smalltalk. (*) Se usa bastante en el mercado, aunque son pocas las empresas que lo utilizan como su lenguaje principal; se suele usar en proyectos medianos o chicos mas que grandes (hay excepciones notables, como MercadoLibre). Tambin se lo usa como herramienta complementaria para el testing y scripting. (-) Eventualmente, si bajas a mucho detalle, el metamodelo de Groovy es complejo y algo inconsistente. Y ocurrirn errores muy raros (que se pueden solucionar). Pero esto normalmente ocurre cuando lo uss a su lmite y jugs mucho con tcnicas de metaprogramacin, cosa que no es el objetivo de diseo. Por eso, esto no debera ser problema, pero igual ests advertido. (-) Para entender los mensajes de error en Groovy, es recomendable entender el metamodelo de Java. Por lo cual, una leda sobre este lenguaje, sus properties (getters y setters) y sobrecarga es una buena idea.Scala: (-) Es sintcticamente mucho mas complejo. De todas formas, el cdigo en general es muy limpio, aunque hay excepciones, sobre todo en lo que concierne a tipos. (-) El metamodelo est inspirado en el de Java, pero no es idntico. Y es ms complejo. Es un hbrido de objetos y funcional. Esto puede traer algunos problemas con algunos fmwks para la JVM; de todas formas, los que usars en la materia (hechos por nosotros), deberan andar bien de una. (*) Tiene tipado esttico e implcito (similar al de Haskell, tiene inferencia).Eso es bueno para detectar errores en el cdigo pronto. De todas formas, su inferencia es ms limitada que la de Haskell, por lo que tendrs que escribir ms informacin de tipo que en Haskell, pero mucha menos que en lenguajes como Java o C. (+) Si tu grupo quieren sacarle el jugo, tiene cosas muy avanzadas (mucho ms que Groovy). Es hoy en da uno de los lenguajes de programacin ms poderosos que existen y uno de los que ms tcnicas de diseo ofrece. (+) El metamodelo, aunque complejo, es muy consistente, por lo que todo cierra y uno puede tener la tranquilidad de que si algo no funciona, es porque est haciendo algo mal y no porque hay un bug en el lenguaje. (+) Aunque no es la panacea, en mi opinin, es uno de los lenguajes del futuro a mediano plazo (ya hay varias empresas que lo estn usando de forma intensiva, ejemplo, Despegar.com).El resumen: ambos lenguajes me parecen buenos para la materia diseo. Y de ambos te podemos dar soporte. Mi consejo: hagan algunos experimentos, bjense los entornos, y vean cual les gusta ms. Algunos links: Referencia de Groovy que usamos en TADP: https://docs.google.com/viewer?a=v&amp;pid=sites&amp;srcid=ZGVmYXVsdGRvbWFpbnx1dG50YWRwfGd4OjczNjhhOWY1NjZmNDQxZjU Pgina de Scala que algunos docentes usan en la materia PHM (de San Martin): https://sites.google.com/site/programacionhm/te/scala" + +} , + +{ + +"title" : "Guia de instalacion de maven", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/guia-de-instalacion-de-maven.html", +"date" : "", +"content" : "IntroduccinMaven es una herramienta que permite automatizar tareas de los desarrolladores, y facilitar el manejo de dependencias, la configuracin de entornos de trabajos locales, entre muchas otras cosas. Por defecto, al instalar Eclipse tambin viene el plugin para utilizar Maven, pero a veces es necesario ejecutar instrucciones adicionales por consola y para eso son estas instrucciones.Instalacin en WindowsRecomendamos seguir este tutorial, ignorando la versin de JDK que es indistinta.Instalacin en SO Unix-based (Linux, Solaris y Mac OS X)Mediante apt-get$sudoapt-getinstallmaven$sudoln-s/usr/share/maven3/bin/mvn/usr/bin/mvnVale la pena aclarar que si bien este mtodo es ms simple, generalmente las versiones de repositorio de Ubuntu suelen estar atrs de las vigentes. Igualmente no les va a traer problemas.ManualmenteDescargar Apache Maven 3 desde este link.Descomprimir el tarball y mover el directorio a donde usualmente se guardan los programas. Ejemplo: /home/john/programs/.$tar-xzvfapache-maven-3.6.0-bin.tar.gz$mvapache-maven-3.6.0/home/john/programs/Agregar la siguiente lnea al archivo .bashrc. Este archivo oculto (su nombre empieza con .) contiene comandos que se ejecutan cuando se abre una terminal (consola). Se puede abrir con cualquier editor de textos (gedit, vim, emacs, notepad++, etc) y se encuentra en el directorio home del usuario.exportPATH=$PATH:$HOME/programs/apache-maven-3.5.0/binUna forma sencilla de hacer sto (sin tener que abrir un editor) es usando el programa echo y agregando al final del archivo el valor ingresado. Prestar atencin al hecho de que se usan dos signos mayor:$echo'exportPATH=$PATH:$HOME/programs/apache-maven-3.5.0/bin'&gt;&gt;.bashrcChequeos posteriores a la instalacinCorroboramos que podemos usar Maven. El output sera algo parecido a ste:john@notebook:~$mvn-vApacheMaven3.5.0(r...)Mavenhome:/home/john/programs/apache-maven-3.6.0Javaversion:1.8...Javahome:/usr/lib/jvm/...Defaultlocale:en_US,platformencoding:UTF-8OSname:"linux",version:"3.0.0-19-generic",arch:"i386",family:"unix"Configuracin de MavenPor defecto no necesits hacer nada, la configuracin por defecto est bien para comenzar a trabajar. Pero en caso de ser necesario algunos ajustes, tens que mirar el archivo settings.xml, que por defecto se ubica en home/usuario/.m2 para sistemas operativos Unix-based C:&#92;Users&#92;Usuario&#92;.m2 para Windows, donde C: es el drive donde se instal Maven si quieren modificar el directorio por defecto, pods chequear esta pregunta en stack overflow. si el archivo no existe, tens que crearlo. Para ms informacin te dejamos la documentacin oficial de la configuracin de MavenPropiedades de Maven en EclipseWindow &gt; Preferences te permite configurar algunas propiedades para Maven. Te recomendamos tener chequeado Do not automatically update dependencies from remote repositories para que no intente bajarte permanentemente nuevas versiones de los componentes que utilices. Esto requiere que lo hagas en forma manual, algo que quizs sea ms recomendable. tener chequeado Download artifact sources te permite ver el cdigo fuente de los .jars que te bajes, esta opcin hace que las descargas inicialmente tarden un poco ms de tiempo pero es bueno cuando tens algn error y necesits entender cmo funciona alguna parte de un componente. tambin es bueno chequear Download artifact javadocs para obtener documentacin de los componentes que utilizamos Y por ltimo tener deschequeada la opcin Update Maven projects on startup permite que manualmente vos actualices los proyectos solamente ante un cambio y no cuando levantes el Eclipse.Una configuracin ms que puede ser til para encontrar versiones nuevas de artefactos en los repositorios es dejar chequeada: La opcin Download repository index on startup (opcin por defecto chequeada): para ms informacin pueden leer http://stackoverflow.com/questions/8647769/what-is-eclipse-doing-when-it-says-that-its-updating-indexes.Material Gua de referencia rpida" + +} , + +{ + +"title" : "Guia de instalacion de rails", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/guia-de-instalacion-de-rails.html", +"date" : "", +"content" : "Guia de Instalacin de RailsIntroduccinRuby On Rails es, entre otras cosas, un framework de presentacin Web MVC, que utiliza el lenguaje de programacin Ruby. Para instalarlo, hay que instalar primero Ruby, algunas herramientas de desarrollo estndar de esta tecnologa, y finalmente, Rails.Antes de empezar Este tutorial asume que ya seguiste la Gua de Instalacin de Ruby Este tutorial asume que ests trabajando en un entorno Linux. Si bien Ruby funciona en Windows, no se recomienda usar Rails en este sistema operativo.PasosInstalar RailsgeminstallrailsCrear un Proyectorailsnew`cd`Configurar la versin de RubyPor ejemplo:rbenvlocal2.0.0-p481Problemas FrecuentesNo se puede instalar SQLITE3Si tienen un error de este estilo:Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./usr/bin/ruby1.9.1-r./siteconf20140902-24182-zuispu.rbextconf.rb/usr/local/lib/site_ruby/1.9.1/rubygems/core_ext/kernel_require.rb:54:in`require':cannotloadsuchfile--mkmf(LoadError)Anerroroccurredwhileinstallingsqlite3(1.3.9),andBundlercannotcontinue.Makesurethat`geminstallsqlite3-v'1.3.9'`succeedsbeforebundling.Verifiquen que instalaron ruby usando rbenv, y rbenv usando rbenv-installer, como explica Guia de Instalacin de Ruby. No usen apt-get para instalar ninguno de estos componentesNo se puede instalar libv8Si tienen un error de este estilo:ERROR:Errorinstallinglibv8:ERROR:Failedtobuildgemnativeextension./usr/bin/ruby1.9.1extconf.rb/usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in`require':cannotloadsuchfile--mkmf(LoadError)from/usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in`require'fromextconf.rb:1:in`&lt;main&gt;'Gemfileswillremaininstalledin/var/lib/gems/1.9.1/gems/libv8-3.11.8.0forinspection.Resultsloggedto/var/lib/gems/1.9.1/gems/libv8-3.11.8.0/ext/libv8/gem_make.outVerifiquen lo mismo que en el ttulo anterior.Falta el runtime de JSSi al intentar levantar el servidor conrailsserverLes dice que falta un JavaScript Runtime, descomenten en en Gemfile la lnea que dicegem'therubyracer'Y ejecuten de nuevobundleinstallMs informacinhttps://gorails.com/setup/ubuntu/14.04" + +} , + +{ + +"title" : "Guia de instalacion de ruby", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/guia-de-instalacion-de-ruby.html", +"date" : "", +"content" : "Gua de Instalacin de RubyIntroduccinLa siguiente es una gua de instalacin de Ruby utilizando un gestin de versiones (rbenv). Si bien este no es estrictamente necesario, simplifica el proceso de instalacin, y es adems fundamental cuando se desea trabajar con mltiples versiones de Ruby, algo bastante comn cuando se est trabajando en ms de un proyecto Ruby en una misma computadora.Esta gua adems instala algunas dependencias que en verdad son slo necesarias para el framework Rails, pero de todas formas las incluimos porque son livianas, fciles de instalar, y previenen problemas futuros.Pasos1. Instalar essentialssudoapt-getinstallcurlgitbuild-essentiallibssl-devautoconfbisonlibreadline6libreadline6-devzlib1gzlib1g-devlibsqlite3-devsqlite3Explicacin: varias herramientas y bibliotecas de Ruby necesitan bajar contenido de Internet, y compilar cdigo nativo.2. Instalar RBENVSeguir las instrucciones en el repositorio de github de rbenv-installer. El resumen es:curlhttps://github.com/rbenv/rbenv-installer|bashecho'exportPATH="$HOME/.rbenv/bin:$PATH"'&gt;&gt;~/.bash_profileecho'eval"$(rbenvinit-)"'&gt;&gt;~/.bash_profileExplicacin: Ruby suele cambiar bastante entre versiones, lo cual genera incompatibilidades. Para no tener problemas, se recomienda instalar Ruby a travs de un manejador de versiones, que adems de simplificar el proceso, permite usar versiones diferentes de esta tecnologa en cada proyecto.Nota: Si usan Ubuntu y lo anterior no funciona revisen estas instrucciones https://github.com/sstephenson/rbenv#installation3. Verificar que se haya instalado rbenvecho$PATHLa linea ~/.rbenv/bin tiene que estar presente. Si no lo est, asegrense de que el cdigo del punto 2 se agreg correctamente en .bashrc o .bash_profile, y de que hayan reiniciado la terminal.4. Instalar una versin de Ruby y dejarlo como opcin por defectorbenvinstall2.0.0-p481rbenvglobal2.0.0-p481rbenvrehashExplicacin: con esto instalamos una versin concreta de Ruby, y la dejamos lista para ser utilizada.5. Instalar BundlergeminstallbundlerExplicacin: Bundler es una herramienta, que al igual que Maven, permite gestionar las dependencias de un proyecto.Problemas frecuentes No se reconoce el comando rbenv: asegrense de que hayan reiniciado la terminal, y que hayan colocado el cdigo de inicializacin en el archivo correcto (.bashrc o .bash_profile, segn qu Linux usen)" + +} , + +{ + +"title" : "Guiso de Lentejas", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/guiso-de-lentejas.html", +"date" : "", +"content" : "Receta para 8 a 10 personas (12 a 15 porciones, la gente repite) 1.5kg de carne repartido a gusto entre: chorizo colorado (no puede faltar) panceta (no puede faltar) carne de vaca, por ejemplo roast beef carne de cerdo, por ejemplo bondiola (opcional) salchicha parrillera 1kg de lentejas 0.5 kg de cebolla 2 papas 2 batatas 1/2 calabaza 2 morrones (uno rojo y uno verde) 3 zanahorias cebolla de verdeo Condimento a gusto sal pimienta pimenton dulce aj molido Queso rallado para el platoPreparacin: Saltar la carne, de a poco, la idea es que est dorada y si metemos todo de una no va a pasar. Si podemos hacer esto sin que se queme el fondo, lo vamos a poder aprovechar en la coccin.Reservar lo ya saltado para ms adelante, separando las carnes que requieren ms coccin (roast-beef, bondiola) de los chorizos, panceta o salchichas. Antes de saltar la carne la podemos cortar en pedazos del tamao de un bocado. Ojo con cortar los chorizos demasiado chicos porque se pueden deshacer del todo. Poner a hervir las lentejas, con la papa, batata y calabaza. Para ganar tiempo, uno puede poner a hervir casi al mismo tiempo que comienza a saltar la carne y apenas saltaste el roast beef y la bondiola los tirs a la olla tambin. No hace falta ser muy puntilloso al cortar la verdura, los pedazos ms chiquitos van a desaparecer en el guiso y los grandes quedan.Slo tener en cuenta que el pedazo ms grande tiene que ser un bocado razonable. Una vez saltada toda la carne, en el fondo de coccin saltar la cebolla, con un poco de sal. De la cebolla de verdeo, pon slo la parte blanca, las hojas verdes las ponemos al final de todo. Vamos raspando un poquito el fondo que la cebolla se lleva todo el fondo de coccin de la carne, el fondo de la olla tiene que quedar limpio en esta operacin. Cuando el cido de la cebolla haya sacado todo lo que haba pegado en el fondo de coccin de la carne, echar el morrn y la zanahoria. Cort la zanahoria bastante chica para que no te quede dura, daditos de menos de 1cm. Al mismo tiempo, ya pods poner la panceta y los chorizos en la olla principal, con las lentejas. Cuando la cebolla est lista, echar todo tambin el la olla principal. Ahora es momento de verificar el condimento. Dejalo hervir hasta que espese, si se ve el agua no es un guiso. Espesa en parte porque el agua se evapora pero tambin porque parte de la verdura se deshace. Apagalo y mezclale las hojas verdes de la cebolla de verdeo. Es mejor dejarlo reposar un rato en la olla, igual en este momento est tan caliente que no lo pods comer, dale 5 o 10 minutos. Idealmente servir en cazuelas y comer con cuchara. No olvidarse de ponerle queso rallado." + +} , + +{ + +"title" : "Herencia", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/herencia.html", +"date" : "", +"content" : "La herencia es un mecanismo que tiene por objetivo principal el compartir lgica/cdigo similar. Esto lleva a evitar la duplicacin de lgica/cdigo. Cuando un objeto recibe un mensaje, mediante Method lookup buscar el comportamiento requerido en la clase de la cual es instancia y, en caso de no tener un mtodo para el mismo, en sus superclases.Herencia SimpleUna clase tiene siempre una superclase pero solo una.Lenguajes que implementan este tipo de herencia: Smalltalk, Java, C#, entre muchos otrosHerencia MltipleUna clase puede tener ms de una superclase.Lenguajes que implementan este tipo de herencia: C++, EiffelGeneralizacinEmpezamos con dos clases, Golondrina (con una variable de instancia energia) y Picaflor (con una variable de instancia energia) , definimos mtodos para ambosSmalltalk#Golondrina&gt;&gt;energia^energia&gt;&gt;come:gramos"Unagolondrinaaumentasuenergiaencuatroveceslosgramosingeridos"energia:=energia+(gramos*4)&gt;&gt;vola:kms"Unagolondrinadisminuyesuenergiaen1Jouleporcadakilometrorecorrido+10Joulesqueutilizaparaeldespegue"energia:=energia-(kms+10)#Picaflor&gt;&gt;energia^energia&gt;&gt;come:gramos"Unpicafloraumentasuenergiaencuatroveceslosgramosingeridos"energia:=energia+(gramos*4)&gt;&gt;vola:kms"Unpicaflordisminuyesuenergiaen1Jouleporcadakilometrorecorrido+20Joulesqueutilizaparaeldespegue"energia:=energia-(kms+20)Wollokclass Golondrina { var energia method energia() { return energia } method come(gramos){ //Unagolondrinaaumentasuenergiaencuatroveceslosgramosingeridos energia=energia+(gramos*4) } method vola(kms) { // Unagolondrinadisminuyesuenergiaen1Jouleporcadakilometrorecorrido+10Joulesqueutilizaparaeldespegue energia=energia-(kms+10) }}class Picaflor { var energia method energia() { return energia } method come(gramos){ //Un picafloraumentasuenergiaencuatroveceslosgramosingeridos energia=energia+(gramos*4) } method vola(kms) { // Un picaflordisminuyesuenergiaen1Jouleporcadakilometrorecorrido+20Joulesqueutilizaparaeldespegue energia=energia-(kms+20) }}Lo que nos permite la idea de generalizacin utilizando herencia es crear nuevas abtracciones.En el cdigo de arriba nos podemos dar cuenta que tanto las golondrinas como los picaflores saben decirnos su energia, comer y volar.Ahora bien, las golondrinas y los picaflores (por ejemplo) saben comer pero adems comen de la misma forma. Estara bueno poder generalizar eso, si las nicos pajaritos con los que estoy trabajando son golondrinas y picaflores puedo decir que todas las aves comen de la misma forma. Entonces generalizo el concepto de Golondrina y Picaflor utilizando una nueva abstraccin, como necesito poner en esa abstraccin mtodos y definir atributos nada mejor que esa nueva abstraccin sea una nueva claseSmalltalk#Ave&gt;&gt;come:gramos"Unaveaumentasuenergiaencuatroveceslosgramosingeridos"energia:=energia+(gramos*4)Wollokclass Ave { method come(gramos){ //Un aveaumentasuenergiaencuatroveceslosgramosingeridos energia=energia+(gramos*4) }Pero no puedo poner ese cdigo en la clase Ave porque esa clase no tiene una variable de instancia energia.Si todas las aves tienen que tener una variable de instancia es algo que me gustara dejar escrito solo en Ave.SmalltalkAvetienedefinidaunavariabledeinstanciaenergiaWollokclass Ave { var energia ....Cmo sigue esto?Tengo que explicitar que las golondrinas tienen todo el comportamiento que esta en la clase Golondrina y tambin tienen el comportamiento que est en la clase Ave. Adems tengo que explicitar que los picaflores tienen todo el comportamiento que esta en la clase Picaflor y tambin tienen el comportamiento que est en la clase Ave.Esto se hace diciendo que Ave es superclase de Golondrina y Ave es superclase de Picaflor; adems tenemos que eliminar el cdigo repetido de las clases Golondrina y Picaflor.SmalltalkEn Smalltalk la forma de crear una clase es envindole el mensaje #subclass:instanceVariableNames:classVariableNames: (o uno similar, depende del dialecto de Smalltalk utilizado) a la superclase de la clase que queremos crear.Superclasssubclass:#NameOfSubclassinstanceVariableNames:'variableInstancia1variableInstancia2variableInstanciaN'classVariableNames:'variableClase1variableClase2variableClaseN'En nuestro ejemploObjectsubclass:#AveinstanceVariableNames:'energia'classVariableNames:''.Avesubclass:#GolondrinainstanceVariableNames:''classVariableNames:''.Avesubclass:#PicaflorinstanceVariableNames:''classVariableNames:''.WollokEn Wollok, lo ponemos directamente en la definicin de las clases, usando la palabra clave inherits:class Ave { var energia = 0 method come(gramos){ //Un aveaumentasuenergiaencuatroveceslosgramosingeridos energia=energia+(gramos*4) }class Picaflor inherits Ave { method vola(kms) { // Un picaflordisminuyesuenergiaen1Jouleporcadakilometrorecorrido+20Joulesqueutilizaparaeldespegue energia=energia-(kms+20) }}class Golondrina inherits Ave { method vola(kms) { // Unagolondrinadisminuyesuenergiaen1Jouleporcadakilometrorecorrido+10Joulesqueutilizaparaeldespegue energia=energia-(kms+10) }}Clase abtractaEn el ejemplo anterior la clase Ave se est usando como superclase de Golondrina y Picaflor. Si nosotros queremos instanciar un ave deberamos elegir si ser una golondrina o un picaflor para mandarle el mensaje new a alguna de esas clases. Lo que no sera correcto es:Smalltalk:unAve:=Avenew.Wollok:var unAve=new Ave()Este cdigo va a funcionar en principio, pero si yo considero que un ave tiene que poder volar y no hay una implementacin en Ave para esta operacin ya que est definido de formas diferentes en sus subclases, unAve no va a entender el mensaje.Entonces, una clase abstracta es aquella que no tiene sentido instanciar porque es demasiado genrica y no tiene una implementacin concreta para algunos mensajes que debera entender porque est definido en sus subclases.Una buena prctica para formalizar el contrato de lo que es ser un ave es definir los mtodos faltantes en la clase Ave de la siguiente forma:Smalltalk#Ave&gt;&gt;vola:unosKilometrosselfsubclassResponsibilityCuando un objeto recibe el mensaje #subclassResponsibility se produce un error indicando que el mtodo debera redefinirse en alguna subclase.WollokSe indica con la palabra clave abstract antes del mtodoclass Ave{ abstract methodvola(unosKilometros)....}De esa forma si agregamos otra subclase de Ave, como ser Gaviota, y olvidamos redefinir vola, cuando una instancia de Gaviota reciba ese mensaje el error ser ms descriptivo que el error de no entender el mensaje, y el desarrollador sabr que las gaviotas deberan definir su forma de volar." + +} , + +{ + +"title" : "Herramientas de desarrollo con android", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/herramientas-de-desarrollo-con-android.html", +"date" : "", +"content" : "LogCatPara poder mostrar informacin en consola, hay que reemplazar los println por Log.v()//Verbose` Log.d()//Debug` Log.i()//Info` Log.w()//Warning` Log.e()//Error`y Log.wtfque muestran los errores por el LogCat, una consola especial de Android.Cmo usarloLog.w("Librex",libro.toString());El primer parmetro indica la aplicacin o agrupador, la segunda es el valor a mostrarCundo usar cada unoLeer esta recomendacinNotificaciones al usuarioEl concepto toast permite enviar al frente un mensaje al usuario sin la incomodidad que tiene el popup de tener que confirmar la lectura de ese mensaje. Es una herramienta til tanto para informar acciones que corrieron en background como para mostrar el estado de la aplicacin en modo desarrollo.Para ms informacin http://developer.android.com/guide/topics/ui/notifiers/toasts.html" + +} , + +{ + +"title" : "Herramientas de instanciación", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/herramientas-de-instanciacion.html", +"date" : "", +"content" : "Llamamos instanciacin a la creacin de un objeto a partir de una clase, la cual define cul es el comportamiento y los atributos que debera tener dicha instancia.Los mecanismos para instanciar objetos a partir de una clase varan bastante entre los distintos lenguajes. En particular, en aquellos lenguajes en los cuales las clases no son a su vez objetos (como Wollok y Java por porner algunos ejemplos) se proveen herramientas para instanciar objetos que se escapan un poquito de la mecnica ms comn de trabajo que es la de enviarle un mensaje a un objeto.En general, desde el punto de vista del uso, lo que los lenguajes proveen es una forma de crear cada instancia indicando cul es la clase que se est instanciando y, en caso de que sea necesario, con qu valores debe inicializarse la instancia en cuestin. De esa forma, el objeto ya estar listo para su uso desde el momento de la creacin.A continuacin se detallan algunas herramientas de construccin a modo de referencia.Inicializacin directaEste es el mecanismo disponible en el lenguaje Wollok en su versin actual. Permite crear instancias de una clase parametrizando los valores iniciales para los atributos que correspondan usando parmetros nombrados. Supongamos que tenemos una clase Golondrina con un atributo energia, cuyo valor por defecto es 100:classGolondrina{varenergia = 100//...todoslosotrosmtodosparalasgolondrinas,//entreloscualeshabrnmuchosquetrabajenconlaenergaasumiendoqueestinicializadaconalgnvalornumrico}Podemos crear una instancia de la clase Golondrina manteniendo el default para la energa de esta forma: new Golondrina(). Si nos interesara crear una golondrina con 25 de energa, la inicializacin directa permite parametrizar esta informacin de esta forma: new Golondrina(energia = 25), y el default simplemente no se usar.En caso de haber varios atributos, pueden inicializarse tantos como querramos, por ejemplo: new Direccion(calle = "Amenabar", numeracion = 140). No importa el orden en el cual se indiquen estos parmetros, solamente debe coincidir con el nombre del atributo que se est inicializando.Esta herramienta, combinada con buenos defaults en caso de que existan, permite construir objetos listos para usar de forma sencilla y con muy poca burocracia.Constructores Nota: Los ejemplos que se muestran a continuacin son en el lenguaje Wollok en sus versiones previas a la 1.8, slo a modo ilustrativo.Los constructores son mtodos especiales cuya finalidad es la creacin de objetos de la clase indicada con la inicializacin de estado interno correspondiente. Para invocarlos se usa la palabra reservada new seguido por el nombre de la clase y los parmetros segn corresponda. Este es el mecanismo que se puede encontrar en varios lenguajes industriales muy usados, como Java y C#, y tambin fue el mecanismo soportado por el lenguaje Wollok en sus primeras versiones (luego se deprec intrudiciendo el mecanismo de inicializacin directa).En general esta forma de definir lgica de inicializacin permite definir ms de un constructor con distinta cantidad de parmetros, de modo que se permita al usuario elegir la forma ms adecuada para crear las instancias. Por ejemplo, las fechas podran permitir instanciarse con un constructor sin parmetros retornando la fecha del da de hoy (porque es muy comn querer obtener instancias con esa configuracin particular, entonces se considera como la inicializacin por defecto si no se indica nada), o con otro de 3 parmetros para que al instanciar la fecha se la inicialice con el da, el mes y el ao deseados:newDate()//retornaralafechadehoynewDate(22,10,2016)//retornaralafechaparaelda,mesyaoespecificados.Esto permite que siempre que obtengamos un objeto, el mismo ya est en condiciones de ser usado en vez de requerir que el usuario recuerde indicar los valores necesarios uno por uno mediante setters, teniendo mientras tanto un objeto con un estado invlido que no puede ser usado.Si no definimos ningn constructor, por defecto la clase viene con un constructor vaco implcito para poder crear los objetos haciendo, por ejemplo: newGolondrina()Supongamos que queremos construir golondrinas con una cantidad de energa que nosotros elijamos como valor inicial, podramos definir:classGolondrina{varenergiaconstructor(_energia){energia=_energia}//...todoslosotrosmtodosparalasgolondrinas,//entreloscualeshabrnmuchosquetrabajenconlaenergaasumiendoqueestinicializadaconalgnvalornumrico}Al definir ese constructor, el constructor vaco por defecto ya no estar disponible para instanciar objetos, de esa forma slo podremos crear objetos con un estado interno vlido en base al constructor particular que hayamos definido.Si el lenguaje que uss usa constructores para definir cmo se inicializan las instancias, asegurate de investigar no slo cuestiones sintcticas, sino tambin qu recaudos hay que tener respecto a la herencia." + +} , + +{ + +"title" : "Herramientas utiles", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/herramientas-utiles.html", +"date" : "", +"content" : "Primeros pasos Amigandonos con el entorno de desarrollo Configuracin de Maven para poder utilizar las herramientas de UqbarMis plugins de eclipseTexLipsePara edicin de latex: http://texlipse.sourceforge.net/Sysdeo.Permite manejar el Tomcat desde dentro del eclipse, se lo baja de: http://www.eclipsetotale.com/tomcatPlugin/tomcatPluginV321.zip.Rinzo.Plugin de eclipse para editar XML y HTML, y se puede bajar de http://sourceforge.net/projects/editorxml/.Tomcat-XT.Extensin al plugin de sysdeo para facilitar la interaccin con Tomcat, lo pueden bajar de ac: http://sourceforge.net/projects/uqbar-tomcat-xt/." + +} , + +{ + +"title" : "Orden superior y calculo variacional (Referencia Externa)", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/high-order-functions-and-variational-calculus.html", +"date" : "", +"content" : "IntroductionShamessly taken from http://web.archive.org/web/20070209204638/http://ergodicity.iamganesh.com/2006/08/07/higher-order-functions/Higher order functionsJoel Spolsky, of the JoelOnSoftware fame, recently wrote about higher order functions in modern languages. While these features have existed for decades in functional programming languages, they have gained a lot of attention lately due to Googles MapReduce technology.Simply put, map and reduce are primitives in languages such as lisp. Thinking in terms of lists (naturally), map lets you apply a function to every element of a list, while reduce lets you combine values of the list in some way. Pick up any lisp book for more details on this programming paradigm.I find a great deal of similarity between functionals in programming, and functionals in variational calculus. Unfortunately, variational calculus is a much neglected field of calculus specially at the undergraduate level. Variational calculus lets you define functions of functions. For example, the functional defined for the continuous function y(t) in the region [a,b]:is the area under the y(t) curve. See how J is completely independent of y(t)? Thats the power of variational calculus.In general, if we have functions of the form:we can use the Euler-Lagrange equations to derive a differential equation to solve the problem.Variational calculus finds much use in diverse fields such as aerospace control (optimize a trajectory based on fuel cost), operations research (optimize FedExs drop off targets based on distance travelled), and image inpainting (total variational models). If you havent figured it out yet, optimization is the reason this entry is posted under Numerical." + +} , + +{ + +"title" : "Home", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/home.html", +"date" : "", +"content" : "Las Homes son objetos que representan a un conjunto de objetos. Hay situaciones donde hay requerimientos que no son propios de ningn objeto en particular sino del conjunto de los mismos. De ah surge la necesidad de tener un objeto que permita representar ese concepto y poder as agregarle esa responsabilidad.De all se desprende que las Homes son objetos que tienen cierta lgica de negocio que aplica a todo un conjunto (por ejemplo en el ejercicio de Atencin Mdica, la HomePrestadores es un buen lugar para poner el mensaje getPrestadoresDisponibles ya que itera sobre todos los Prestador). Pero no debera convertirse en un God Object, sino que debera delegar en algn punto en otros objetos. En general deberan slo tener la lgica que aplica a nivel de grupo para luego delegar en los objetos que contiene.Tampoco se debe confundir la Home con el punto de entrada a todos los casos de uso. Los casos de uso deberan comenzar desde el objeto de negocio que corresponda, que puede o no ser una Home.La idea de Home no tiene que ver con performance, o base de datos." + +} , + +{ + +"title" : "Html", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/html.html", +"date" : "", +"content" : "HTMLHTML (HyperText Markup Language) es el lenguaje principal que se utiliza para construir pginas web. Es un lenguaje declarativo que permite describir el contenido de una pgina.Estructura General de una pgina HTMLSintaxisEl HTML es un lenguaje de etiquetas o marcas. Por cada etiqueta que abre hay otra igual pero que cierra, se escribe igual pero con una / adelante.&lt;html&gt;&lt;/html&gt;&lt;h3&gt;&lt;/h3&gt;La notacin inline permite abrir y cerrar el tag en un mismo paso:&lt;img /&gt;&lt;br/&gt;&lt;hr/&gt;Si bien muchos browsers relajan la sintaxis de apertura y cierre de tags (como en los casos de &lt;ul&gt; y &lt;br&gt;) es una buena prctica respetar esta idea, lo que permite definir XHTML o HTMLs bien formados.Tag HTMLCada tag puede tener contenido, que es un texto atributos, demarcados con una clave y un valor otros tags, que se anidan en forma jerrquica&lt;tag atributo1="valor1" atributo2="valor2"&gt; contenido con &lt;otrotag&gt;otro subcontenido&lt;/otrotag&gt;&lt;/tag&gt;Estructura de una pgina HTMLEl contenido de una pgina web se estructura en forma jerrquica. A partir de HTML 5 tenemos tags especiales que permiten definir una semntica estndar para nuestro documento: un encabezado o header principal de la pgina el cuerpo principal o body, que arma el contenido de la pgina y puede agrupar tags visuales y los de contenido, como section y article: que sirven como elementos que agrupan contenido, y que pueden a su vez tener elementos head, footer o nuevos section/article nav: que contiene links de navegacin aside: elementos que no forman parte del contenido principal un pie de pgina o footer principal de la pginaEjemploUn ejemplo posible de estructuracin del body de una pgina puede ser:&lt;section&gt; &lt;h1&gt;El pato&lt;/h1&gt; &lt;section&gt; &lt;h1&gt;Introduccin&lt;/h1&gt; &lt;p&gt;En esta seccin, ampliaremos nuestro concepto del pato.&lt;/p&gt; &lt;/section&gt; &lt;section&gt; &lt;h1&gt;Hbitat&lt;/h1&gt; &lt;p&gt;Esta especie de animal lleg en tiempos remotos, trados en diversas expediciones desde Europa y China, se fueron expandiendo por todo el mundo rpidamente y debido a su temperamento fueron criados como animales domsticos para el consumo de su carne y huevos, as como para mascotas en muchos hogares.&lt;/p&gt; &lt;/section&gt; &lt;aside&gt; &lt;p&gt;otros estudiosos del pato&lt;/p&gt; &lt;/aside&gt;&lt;/section&gt;&lt;footer&gt; &lt;p&gt;(c) 2010 The Example company&lt;/p&gt;&lt;/footer&gt;Anlisis semntico de un HTMLEsto permite que haya plugins como el HTML 5 Outliner que pueda ordenar los elementos segn su orden de importancia (la jerarqua la define el nivel de anidamiento dentro de HTML pero tambin el tag le dice semnticamente a qu corresponde cada contenido).Aqu vemos que algunas pginas estn semnticamente mejor ordenadas que otras: a veces no hay un ttulo que identifique la seccin, o no se respeta bien el orden jerrquico de los contenidos.En Firefox tenemos el add-on headingsMap que construye una estructura en paralelo para navegar las pginas de otra manera (para por ejemplo ordenar las noticias segn las ms ledas):Links relacionados Temario Algoritmos III W3 - Web Architecture" + +} , + +{ + +"title" : "Hugs trex insertfield not in scope", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/hugs-trex-insertfield-not-in-scope.html", +"date" : "", +"content" : "Si estn en Hugs y luego de cargar su programa aparece el siguiente error:Haskell 98 does not support extensible records ERROR - Hugs.Trex.insertField not in scope Possible cause: Hugs.Trex module not imported Revisen que en sus funciones no estn usando = para comparar dentro de la definicin de una funcin. Para comparaciones por igualdad se usa ==" + +} , + +{ + +"title" : "Igualdad vs. Identidad", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/igual-o-identico-----vs---.html", +"date" : "", +"content" : "DefinicionesIdentidad: decimos que dos objetos son idnticos si son el mismo objeto. Dentro del ambiente podemos tener dos referencias diferentes al mismo objeto. En Wollok el operador usado para comparar dos objetos por identidad es ===.Igualdad: (o equivalencia) por defecto dos objetos son iguales si son idnticos, o sea si son el mismo objeto. A diferencia de la identidad, la igualdad puede ser redefinida con una implementacin especfica si el problema lo amerita. En Wollok el operador usado para comparar dos objetos por igualdad es ==.EjemplosAlgunos objetos literales como los nmeros o los booleanos son nicos en el sistema, por ese motivo evaluar 3 === 3 da true al igual que 3 == 3.Sin embargo, lo normal es hacer las comparaciones con == y no con ===, ya que en general lo que interesa saber es si dos objetos son iguales desde el punto de vista de dominio. Un ejemplo muy comn son los strings: supongamos que queremos saber si el resultado de concatenar hola con mundo es el string holamundo. No es relevante si el resultado de esa concatenacin fue exactamente el mismo objeto que se puede obtener al escribir el literal holamundo, de hecho, es normal que no lo sea:&gt; "hola" + "mundo" == "holamundo"=&gt; true&gt; "hola" + "mundo" === "holamundo"=&gt; falseDando un paso ms, en qu casos podra ser til redefinir la igualdad? Hay algunos objetos que tienen como principal objetivo representar datos ms all de los literales que ya conocemos, como ser las fechas. Si evaluamos esto en una consola:&gt; const fecha1 = new Date(day = 24, month = 11, year = 2017)&gt; const fecha2 = new Date(day = 24, month = 11, year = 2017)Luego podemos confirmar que la igualdad para las fechas est definida en trminos de los datos, la identidad no es relevante:&gt; fecha1 == fecha2=&gt; true&gt; fecha1 === fecha2=&gt; falseImportante Slo debera redefinirse la igualdad basado en valores que no vayan a cambiar. Por ejemplo si quisiramos modelar una direccin que tiene como atributos la calle y la numeracin y nos interesara definir la igualdad en esos trminos, es importante que una vez construido el objeto direccin con la calle y la numeracin, no sea posible cambiar esas referencias, ya que la relacin de igualdad entre dos objetos debera mantenerse a lo largo del tiempo. O sea, el objeto no necesita ser totalmente inmutable pero s debemos garantizar que mnimamente lo sea respecto a los valores usados para la igualdad.Otra cosa a tener en cuenta si se redefine la igualdad es que podran existir otros objetos del sistema (como las colecciones) que se basan en otro mensaje (suele llamarse hash o hashCode) para encontrar rpidamente objetos que son (o podran ser) iguales al receptor de dicho mensaje, es comn que se use para algoritmos de bsqueda. Su particularidad es que, en vez de recibir otro objeto por parmetro para poder compararlo, no recibe parmetros y retorna un nmero al que se denomina cdigo de hash. En general si la igualdad se define de una forma particular y se mantiene la forma de calcular el cdigo de hash predefinida, eventualmente surgirn comportamientos inesperados. Por eso, independientemente de la tecnologa que uses, asegurate de averiguar cal es la forma ms adecuada de implementar ese mensaje.En el caso del ejemplo planteado de las direcciones, podra ser razonable que la igualdad se defina preguntando si la calle de la direccin que recibi el mensaje es igual a la calle de la otra direccin y adems la numeracin de esa direccin tambin es igual a la numeracin de la otra direccin. Luego el cdigo de hash podra obtenerse mediante un clculo que involucre tanto al cdigo de hash de la calle de la direccin que recibi el mensaje y tambin al cdigo de hash de su numeracin." + +} , + +{ + +"title" : "Portada", +"category" : "", +"tags" : "", +"url" : "/", +"date" : "", +"content" : ""Generar una forma de pensar crtica, rigurosa, donde no cabe el dogma, la fe ni el principio de autoridad para sustentar un argumento" (1)PortadaHola!Bienvenidos a la herramienta colaborativa del grupo Uqbar. Somos un grupo de docentes, investigadores y alumnos de diferentes universidades de la Argentina que enseamos, aprendemos y trabajamos en diferentes temas relacionados con la construccin de software.El objetivo de esta pgina es proveer un lugar integrado en el cual agrupar y organizar el conocimiento con el que trabajamos, que sirva tanto para compartirlo entre las distintas universidades en las que nos desempeamos como para la comunidad en general. Tambin nos permite publicar material asociado con las asignaturas pero que muchas veces por motivo de espacio no es posible abordarlo durante la cursada, as que este es el lugar en el que el estudiante curioso puede ir un poquito ms all de lo que podemos alcanzar a ver en clase.Si sos un estudiante en busca del material de una materia, tal vez te convenga ingresar por uno de estos links:UTN Paradigmas de Programacin Diseo de Sistemas Tcnicas Avanzadas de ProgramacinUNSAM Algoritmos II Algoritmos III Programacin con Herramientas ModernasMaterial adicionalPara el que busca algo que vaya ms all de lo visto en las clases aqu hay una lista con algunos artculos sobre otros Temas Interesantes de Programacin. Finalmente, otra posibilidad es browsear nuestra coleccin de propuestas de Herramientas tiles, que incluye tanto herramientas propias como algunas herramientas de terceros que recomendamos.Discusiones Robustez de los lenguajes Lombardizacin Comidas Portal del investigador Tips para Concursos Docentes Coeficiente de Felicidad Docente" + +} , + +{ + +"title" : "Inferencia de tipos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/inferencia-de-tipos.html", +"date" : "", +"content" : "Entendemos por inferencia de tipos la capacidad que tienen algunos lenguajes con chequeo esttico de tipos para calcular el tipo de una expresin, funcin o variable sin necesidad de contar con anotaciones de tipo como s se necesitan en C y Java por ejemplo.La clave de este proceso es la regla por la cual se obtiene el tipo de la aplicacin de una funcin:f::AB-&gt;e::A-------------------fe::BEn trminos ms mundanos, lo que la regla dice es: si f es una funcin cuyo dominio es A e imagen es B y, si e es una expresin de tipo A entonces, el tipo de f e (usamos a e como argumento de f) es BEjemplo, el tipo de not False se puede inferir con esta regla: si not es una funcin cuyo dominio es Bool e imagen es Bool y, si False es una expresin de tipo Bool entonces, el tipo de not False es BoolOtro ejemplo, si queremos saber de que tipo es la expresin not 3 vemos que no tiene un tipo siguiendo la regla que especificamos anteriormente, porque requerira que 3 sea de tipo Bool pero 3 no es un booleano.Expresiones como not 3, 2 + True, length (4,3), fst [1,2], etc. no tienen un tipo y por lo tanto no son expresiones vlidas en Haskell. Analicemos el siguiente caso:funcionLocax|x&gt;0=1|otherwise=TrueComo por una rama retornamos un Int (1 :: Int) y por la otra retornamos un Bool (True :: Bool) no se puede obtener la imagen de la funcin funcionLoca, ergo la funcionLoca no se puede escribir en Haskell porque no tiene un tipo.Sin embargo, que una expresin tenga tipo no significa que sea una expresin libre de errores.head::[a]-&gt;ahead[]::aPero a pesar de esto, si evaluamos la expresin&gt;head[]ErrorComo la inferencia de tipos es un proceso ANTERIOR a la evaluacin, los programas que hacemos en Haskell son Type SafeLa inferencia de tipos es una caracterstica del paradigma funcional?S, es un concepto que fue desarrollado primero en el contexto del paradigma funcional e histricamente se lo ha encontraro principalmente asociado a lenguajes funcionales; sin embargo la idea de inferencia no est limitada este tipo de lenguajes y cada vez ms est siendo utilizada en todo tipo de lenguajes.Algunos lenguajes que poseen formas de inferencia de tipos son: Ada, BitC, Boo, C# 3.0, Cayenne, Clean, Cobra, D, Delphi, Epigram, F#, Haskell, haXe, JavaFX Script, ML, Mythryl, Nemerle, OCaml, Oxygene, Scala.Por otro lado, la inferencia es ms simple en los lenguajes que no permiten realizar asignaciones; y eso hace que sea ms fcil de implementar en los lenguajes declarativos puros como Haskell.EjemplosVer Clculo del tipo de una funcin en HaskellRecuerden que en Haskell ustedes pueden obtener el tipo de cualquier expresin escribiendo :t (type) en el interprete&gt;:tnotnot::Bool-&gt;Bool&gt;:tnotFalsenotFalse::Bool&gt;:tnot3ErrorProblemas de inferencia en HaskellSi bien Haskell puede inferir correctamente el tipo de las funciones que definimos casi siempre, existen casos en los cuales necesita un poco de ayuda de parte del programador. En caso de que eso pase, conviene explicitar el tipo de nuestra funcin adems de su definicin en el .hs.Por ejemplo, si estamos haciendo una funcin f que recibe una lista de a y retorna una lista de a, podemos hacer:f::[a]-&gt;[a]flista=&lt;lo que sea que hay que hacer con la lista para retornar otra&gt;" + +} , + +{ + +"title" : "Inject into", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/inject-into-.html", +"date" : "", +"content" : "El inject:into: es un solo mensaje que entienden todas las colecciones, recibe 2 parmetros.UtilidadLa idea de este mensaje es realizar una operacin de acumulacin sobre todos los elementos de una coleccin.Parmetros del inject:into:El primero parmetro del inject:into: (valorInicialAcumulador) representa el objeto al cual va a apuntar el acumulador antes de empezar a evaluar el bloque (el 2do parmetro del inject:into:) sobre cada elemento de la coleccin.El segundo parmetro del inject:into: (bloqueConDosParametros) es un bloque que va a ser evaluado sobre cada elemento de la coleccin y el acumulador actual. bloqueConDosParametros = [ :acumuladorActual :elementoDeLaColeccion &#92;] El inject:into: retorna el valor final del acumuladorEjemplosSumatoria de una coleccin de nmerosSi col es una coleccin de nmeros y queremos obtener su sumatoria podemos hacercolinject:0into:[:sumatoria:numero|sumatoria+numero]valorInicialAcumulador = 0acumulador = sumatoriaelementoDeLaColeccion = numerooperacin que retorna el nuevo valor del acumulador = sumatoria + numeroProductoria de una coleccin de nmerosSi col es una coleccin de nmeros y queremos obtener su productoria podemos hacercolinject:1into:[:productoria:numero|productoria*numero]valorInicialAcumulador = 1acumulador = productoriaelementoDeLaColeccion = numerooperacin que retorna el nuevo valor del acumulador = productoria * numeroMximo de una coleccin de nmerosSi col es una coleccin de nmeros y queremos obtener el mximo podemos hacercolinject:colanyOneinto:[:maximo:numero|maximomax:numero]valorInicialAcumulador = col anyOne (algn elemento de la coleccin)acumulador = maximoelementoDeLaColeccion = numerooperacin que retorna el nuevo valor del acumulador = maximo max: numeroLa altura ms alta de una coleccin de personasSi col es una coleccin de personas y queremos obtener la altura ms altacolinject:colanyOnealturainto:[:maximaAltura:persona|maximaAlturamax:personaaltura]valorInicialAcumulador = col anyOne altura (alguna altura de alguna persona de la coleccin)acumulador = maximaAlturaelementoDeLaColeccion = personaoperacin que retorna el nuevo valor del acumulador = maximaAltura max: persona alturaLa persona ms alta de una coleccin de personasSi col es una coleccin de personas y queremos obtener la persona ms altacolinject:colanyOneinto:[:personaMasAlta:persona|personaMasAltaaltura&gt;personaalturaifTrue:[personaMasAlta]ifFalse:[persona]]valorInicialAcumulador = col anyOne (alguna persona de la coleccin)acumulador = personaMasAltaelementoDeLaColeccion = personaoperacin que retorna el nuevo valor del acumulador = personaMasAlta altura &gt; persona altura ifTrue: [personaMasAlta] ifFalse: [persona]Nota: si asumimos que persona es instancia de la clase Persona podemos hacer lo siguientecolinject:colanyOneinto:[:personaMasAlta:persona|personaMasAltapersonaMasAlta:persona]Persona&gt;&gt;personaMasAlta:otraPersona^selfaltura&gt;otraPersonaalturaifTrue:[self]ifFalse:[otraPersona]Aplanando coleccionesSi col es una coleccin donde cada uno de sus elementos son colecciones y quiero obtener una coleccin con todos los elementos de sus subcolecciones puedo hacercolinject:Bagnewinto:[:unaColeccionConTodosLosElementos:unaColeccion|unaColeccionConTodosLosElementosaddAll:unaColeccion.unaColeccionConTodosLosElementos]"HayqueretornarexplcitamenteunaColeccionConTodosLosElementos"Si no nos interesan los elementos repetidos podemos escribircolinject:Setnewinto:[:unaColeccionConTodosLosElementos:unaColeccion|unaColeccionConTodosLosElementosunion:unaColeccion]Al menos en Pharo recordar que: #union: retonarna una instancia de Set #add, #addAll:, #remove:, #removeAll: retornan el objeto que recibieron como parmetro NO retornan al objeto receptor del mensaje " + +} , + +{ + +"title" : "Inmutabilidad", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/inmutabilidad.html", +"date" : "", +"content" : "El concepto de inmutabilidad est asociado a la ausencia de cambio. En los paradigmas Funcional y Lgico, la inmutabilidad est garantizada, ya que no es posible modificar los datos con los que trabaja una funcin o un predicado, en todo caso lo que se puede hacer para emular un cambio sobre una estructura es retornar o relacionar con una nueva estructura a partir de la original con la informacin que tendra como consecuencia de la transformacin deseada.Por ejemplo, si en Haskell quisiramos representar que una persona de la cual conocemos su nombre y su edad cumpla un ao tendramos que definir una funcin como esta:data Persona = Persona String IntcumplirAos :: Persona -&gt; PersonacumplirAos (Persona nombre edad) = Persona nombre (edad + 1)En los paradigmas en los cuales se trabaja con efecto colateral trabajar de forma inmutable es una decisin de diseo. Pensemos un poco en el paradigma de objetos.Decimos que un objeto es inmutable si no puede cambiar su estado interno (su conjunto de atributos) despus de su inicializacin.Los Strings son un ejemplo de objetos inmutables, cualquier operacin que hagan sobre un string (concatenacin, cambiar a mayscula o minscula, etc) slo retorna otro string, el receptor nunca se modifica.Si la interfaz del objeto tiene una forma de inicializar sus variables, pero no exhibe el comportamiento para settear sus atributos, sus usuarios no podrn alterar su estado interno ms adelante. Para construir un objeto ya inicializado solemos usar mtodos de clase u otras herramientas de instanciacin, de esa forma no ser necesario usar setters para configurar un estado que no sera esperable que cambie luego de la construccin del objeto.Que un objeto sea inmutable permite que pueda ser compartido por varios objetos sin que puedan afectarse entre s, ya que no hay nada que puedan hacer sobre ese objeto compartido que produzca un cambio visible para el otro objeto que lo conoce.Es importante tener en cuenta que no alcanza en algunos casos con que el objeto no exhiba comportamiento que permita mutarlo, ya que podra tener un atributo que referencie a un objeto que s es mutable. Luego si alguien le manda un mensaje que retorna a ese objeto mutable, y a ese objeto le manda un mensaje que lo modifica, el objeto inicial habr sufrido cambios.Volviendo al caso de los Strings, estos objetos estn compuestos por otros objetos que representan a los caracteres, qu pasa si al string hola le pido su primer elemento y a ese caracter $h le mando un mensaje para que se cambie a mayscula, luego el string original ya no sera hola sino, Hola, no? Eso no es un cambio sobre el string tambin??Bueno, como resulta que los caracteres tambin son inmutables, realmente no hay nada que se pueda hacer para que el string cambie.Entonces, si estamos haciendo nuestros propios objetos inmutables, hay que tener en cuenta si los objetos que conocen pueden o no cambiar su estado. En el caso de que no, listo, pero si s pueden, hay que plantearse si dichos objetos no deberan ser tambin inmutables, y en el caso de no querer que as sea, retornar copias de los mismos cuando sea necesario. De esa forma, quien enve el mensaje que retorna uno de estos objetos mutables, pueda realizar modificaciones sobre el mismo sin que el objeto inmutable se vea afectado.Otra cosa a mencionar es sobre los objetos inmutables es que la igualdad ya no se basa en la identidad. Debera ser cierto por ejemplo que hola sea igual a ho concatenado con la, independientemente de que sean o no el mismo objeto. La igualdad termina dependiendo de los valores de sus atributos (o un subconjunto de ellos). Por eso es muy comn redefinir la igualdad para los objetos inmutables." + +} , + +{ + +"title" : "Intro a colecciones", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/intro-a-colecciones.html", +"date" : "", +"content" : "Las colecciones nos resultan de utilidad porque nos permiten agrupar objetos, para luego poder operar sobre un elemento en particular, sobre algunos elementos seleccionados mediante un filtro, o sobre una coleccin como conjunto.Esto nos permite modelar conjuntos o agregados de cosas, que son muy comunes en casi todos los dominios en los que podemos pensar: las piezas de un tablero de ajedrez, los integrantes de un equipo de ftbol, las lneas de una factura, de todo!A primera vista una coleccin es un conjunto de objetos. Si la vemos con ms precisin nos damos cuenta que es ms preciso pensarla como un conjunto de referencias: los elementos no estn adentro de la coleccin, sino que la coleccin los conoce. Y como no poda ser de otra forma, las colecciones tambin son objetos.No hay un nico tipo de coleccin, hay distintos sabores de colecciones que nos van a servir para distintos fines, sin embargo la mayora de las colecciones entiende un conjunto grande de mensajes en comn, o sea, son polimrficas :) Slo van a diferir en algunos mensajes particulares debido a la naturaleza de la coleccin.Qu podemos hacer con una coleccin?Para tratar de responder esta pregunta no es necesario estar familiarizado con la implementacin de las colecciones. Recordemos que una de las caractersticas ventajosas del Paradigma de Objetos es que acerca nuestro modelado a la forma en que percibimos la realidad.Entonces que haramos nosotros con una coleccin? Pensemos en una coleccin de estampillas. Podemos: Mirarlas -&gt; recorrer la coleccin y hacer algo con cada elemento Encuadernarlas por fecha -&gt; ordenar la coleccin Conseguir nuevas estampillas -&gt; agregar elementos a la coleccin Regalar una estampilla -&gt; quitar elementos de la coleccin. Quedarme con las estampillas de Brasil -&gt; hacer un filtro o seleccin de los elementos segn un criterio. Saber si tengo una determinada estampilla -&gt; preguntarle a una coleccin si incluye o no un determinado objeto como elemento.Qu otra coleccin podemos modelar del mundo real? Un carrito del supermercado!!Mientras vamos de gndola a gndola del super vamos agregndole elementos (referencias a objetos) a esa coleccin. Cuando llegamos a la caja recorremos esa coleccin y obtenemos informacin de la misma: cunto suma el costo total de sus artculos, cuntos artculos comprAhora, como podemos modelar todas estas situaciones en objetos? Enviando mensajes a colecciones! Recordemos que en el paradigma de objetos todo programa es un conjunto de objetos envindose mensajes para concretar un objetivo en comn. Bien, en este caso los objetos sern las distintas colecciones y sus elementos. Los mensajes que puede recibir una coleccin sern dependientes del lenguaje, claramente, pero la idea detrs es bsicamente la misma.Un ejemplo rpido en Wollok: En este ejemplo vamos a usar un tipo de coleccin al que llamamos Set. Supongamos que tenemos 4 objetos distintos que son estampillas (nos interesa que nos sepan decir su origen y su superficie, no importa cmo lo hacen), agreguemos algunas a la coleccin.varcoleccionEstampillas=#{}coleccionEstampillas.add(estampillaBrasileraGrande)coleccionEstampillas.add(estampillaAlemana)coleccionEstampillas.add(estampillaBrasileraMediana)Alternativamente, si ya conozco los elementos que va a tener inicialmente, usando el set literal de Wollok podemos crear directamente la coleccin con esos elementos.varcoleccionEstampillas=#{estampillaBrasileraGrande,estampillaAlemana,estampillaBrasileraMediana}A esta coleccin de estampillas ya le puedo hacer algunas preguntascoleccionEstampillas.size()//devuelve3coleccionEstampillas.contains(estampillaAlemana)//devuelvetruecoleccionEstampillas.contains(estampillaBrasileraChica)//devuelvefalseClaro que para que la coleccin me sea realmente til, me debe permitir interactuar con sus elementos, poder hablarle (p.ej.) a estampillaAlemana a travs de la coleccin. Antes de ver cmo hacer esto, clarifiquemos un poco la relacin entre una coleccin y sus elementos.Colecciones y referenciasComo ya dijimos en la introduccin, si miramos una coleccin en detalle, vemos que es mejor entenderla como un conjunto de referencias a objetos, y no como un conjunto de objetos. Cul es la diferencia? Que conceptualmente, la coleccin no tiene adentro suyo a sus elementos.Los elementos de una coleccin son objetos como cualesquiera otros, al agregarlos a una coleccin estoy, en realidad, agregando una referencia que parte de la coleccin y llega al objeto agregado. Los objetos que elijo agregar una coleccin pueden estar referenciados por cualesquiera otros objetos.En el ejemplo anterior, algunas de las estampillas que creamos son elementos de la coleccin, y adems estn referenciadas por variables. Grficamente tenemos: Si se estn preguntando en qu orden estn las estampillas en el Set? Un Set no mantiene sus elementos en un orden determinado, ms adelante veremos que hay distintos sabores de colecciones, algunos mantienen orden y otros no. En este momento, no es lo que nos interesa.Ahora agreguemos un objeto ms: pedro, el coleccionista, que sabe cul es su estampilla favorita (la estampillaBrasileraMediana). El ambiente queda as:Ahora hay un objeto que tiene 3 referencias: es el objeto referenciado por la variable estampillaBrasileraMediana es un elemento del Set es la estampilla preferida de pedro Ya podemos ver un poco ms en detalle la relacin entre una coleccin y sus elementos. La coleccin maneja referencias a los elementos que le voy agregando (p.ej. envindole el mensaje add(elemento) ), anlogas a las referencias de las variables de instancia de otros objetos. Hay dos diferencias entre las referencias que mantiene una coleccin y las que mantienen nuestros objetos p.ej. pedro: Las referencia que usan nuestros objetos tienen un nombre, que es el nombre que luego usar para hablarle al objeto referenciado; las de la coleccin son annimas. Nuestros objetos tienen una cantidad fija de referencias (en este caso pedro tiene una nica referencia, estampillaPreferida), una coleccin puede tener una cantidad arbitraria, que puede crecer a medida que le agrego elementos.As, los objetos que quedan referenciados por la coleccin pueden tener otras referencias sin problema. Un objeto no tiene nada especial por ser elemento de una coleccin, slo tiene una referencia ms hacia l. Un objeto no conoce de qu colecciones es elemento (podra tener una referencia explcita a la coleccin para saberlo, pero eso habra que programarlo a mano y por lo general tampoco nos interesa).La referencia a un objeto por ser elemento de una coleccin cuenta para que el objeto no salga del ambiente cuando pasa el Garbage collector. Eso significa que si dejamos de referenciar a nuestra estampilla alemana mediante la referencia estampillaAlemana, como la coleccin de estampillas la conoce, el objeto va a seguir en el sistema.Hablando con los elementosHay algunas operaciones que se hacen sobre una coleccin en las cuales parte de lo que hay que hacer es responsabilidad de cada elemento.Por ejemplo, supongamos que quiero obtener de mi coleccin de estampillas aquellas que tengan ms de 10 cm2 de superficie. La coleccin no sabe la superficie de cada estampilla, s conoce a las estampillas, entonces puede enviarle mensajes a cada una. Lo que no sabe es qu mensajes puede enviarle, un Set no sabe si lo que tiene son estampillas, perros, nmeros, otros Set, o cualquier otro objeto, slo representa al conjunto, sin saber nada de sus elementos. Por otro lado, cada estampilla no sabe en qu coleccin est, de hecho un mismo objeto podra estar en varias colecciones.Por lo tanto, para resolver mi problema necesito que acten tanto la coleccin (que es la que conoce a los elementos) como cada elemento (que es el que sabe su superficie). Veamos cmo lograr esta interaccin. Empecemos por decidir a quin le pedimos lo que queremos. Quiero aquellas estampillas, de las que son elementos de coleccionEstampillas, que cumplan una determinada condicin.A qu objeto le voy a pedir esto? A la coleccin.El mensaje es filter(algo) en Wollok o sea que necesita un parmetro. Este parmetro va a representar una condicin para el filtrado, que es un cdigo que la coleccin debera evaluar sobre cada elemento, y debe devolver true o false para que la coleccin sepa si debera o no estar en la coleccin nueva a devolver.Los objetos que representan cachos de cdigo son los Bloques, en este caso un bloque con un parmetrocoleccionEstampillas.filter({estampilla=&gt;estampilla.superficie()&gt;10})Mientras que todos los elementos de la coleccin entiendan el mensaje superficie y al recibirlo retornen un nmero, el filtrado va a funcionar correctamente.En resumen: cuando quiero hacer una operacin sobre una coleccin que necesita enviarle mensajes a cada elemento, la operacin se la pido a la coleccin, y le voy a enviar como parmetro un bloque que describe la interaccin con cada elemento." + +} , + +{ + +"title" : "Introduccion a las metodologias de desarrollo de software", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/introduccion-a-las-metodologias-de-desarrollo-de-software.html", +"date" : "", +"content" : "Para qu sirve una metodologa?Una metodologa nos ordena, nos contiene, nos permite definir lmites. Construir software complejo requiere un gran esfuerzo: tecnologa, dinero y sobre todo: personas. Personas que interactan entre s, con diferentes grados de conocimiento, con diferentes roles, con diferentes intereses. Una metodologa propone un esquema de trabajo que nos permite entender cul es nuestro rol dentro del proyecto, nos acerca una cierta sensacin de tranquilidad, de seguridad. Sin un proceso no sabemos cmo comenzar y cundo terminar.Metodologas secuenciales / iterativasEn las metodologas secuenciales, el proceso de desarrollo de software se divide en varios pasos o fases. Cada fase tiene un conjunto de metas a cumplir. El fin de cada fase delimita el comienzo de la fase siguiente. Aunque son normales la superposicin de fases, estas metodologas proponen una gran fase de anlisis de requerimientos, otra de diseo, otra de construccin y otra de pruebas donde el alcance de cada fase es la totalidad de los requerimientos de un proyecto.En las metodologas iterativas se divide el proyecto en entregas o iteraciones. Si cada iteracin define un conjunto de metas a cumplir, podramos pensar que no hay una gran diferencia con la metodologa secuencial. No obstante, cada iteracin define como entregable un software testeable por el usuario. Entonces hay etapas de anlisis de requerimientos, diseo, construccin y prueba en cada iteracin. Adems, cada iteracin permite revisar y cambiar los requerimientos a resolverse.Metodologas orientadas al proceso / a las personasOtra taxonoma que divide las metodologas es el grado de importancia que le dan al proceso de desarrollo y a las personas que ejecutan ese planSi bien la mayora de las metodologas contemplan tanto la serie de pasos que conforman el proceso como qu tipo de tareas deben desarrollar las personas (en base a sus perfiles), hay metodologas en las que el proceso est por encima de las personas. Dicho de otra manera, respetar el proceso garantiza el xito del proyecto. El margen de discrecionalidad (cunto puedo salirme del libreto) es mnimo, slo en lo operacional (en el da a da). Por eso es importante para estas metodologas poder medir cada tarea del proyecto, sea un ejecutable o documentacin.Por el contrario, las metodologas orientadas a las personas consideran que stas definen el xito o fracaso de un proyecto. Les asignan un grado mayor de decisin en cada tarea y confan en su capacidad de resolucin de un problema antes que en las mtricas que dan los indicadores. Esto no quiere decir que el proceso no importe, sino que ocupa un puesto de menor relevancia en la consecucin de un logro.Metodologas orientadas a la documentacin / al productoHay metodologas que sostienen que un producto de software bien elaborado nace de una documentacin extensa y que contemple todas las decisiones que surgieron del anlisis y del diseo. De esa manera el desarrollador no tendr dudas ni excusas a la hora de escribir cada lnea de cdigo.Por el contrario, hay metodologas que privilegian tener un software testeable para el usuario antes que tener el documento que respalde ese software que est corriendo. Esto no significa que haya que programar sin tener una especificacin, sino que: tomamos una documentacin que puede tener definiciones pendientes, estar incompleta en su diseo o que sepamos que est sujeta a cambios construimos el software y luego actualizamos las decisiones principales en el documentocon la ventaja de tener la certeza de que lo que hace el sistema es eso.Metodologas predictivas / adaptativasQu ocurre con los cambios que piden los usuarios mientras se va construyendo el software? Cmo se manejan? algunas metodologas creen que es posible anticipar los cambios a travs de un buen anlisis y un buen diseo que contemple diferentes alternativas. Este enfoque no es inocente, sabe perfectamente que el usuario puede cambiar de opinin, que las disposiciones legales e impositivas sufren modificaciones y que los proyectos estn siempre sujetos a vaivenes polticos. Pero justamente por eso busca minimizar los cambios para conservar lo ms estable posible el entorno: resistirse al cambio es su naturaleza. otras metodologas consideran que el cambio es inevitable, que no tiene sentido resistirse a l. De manera que el proceso mismo contempla momentos en los que el usuario puede modificar los requerimientos: esto implica agregar nuevos, descartar otros o modificarlos (no importa si ya fueron construidos o no). El usuario tiene derecho a cambiar de opinin, sostienen.Algunos ejemplos Modelo de Cascada: nunca existi, fue una maliciosa interpretacin del paper de Winston Royce: Managing the development of large software systems. Les recomendamos ver este interesante video al respecto, para entender lo inapropiado y excesivamente optimista que es aplicar esta metodologa en un proceso de desarrollo actual. Espiral de Boehm: originado en el paper de Barry Boehm: A Spiral Model of Software Development and Enhancement, surge como primer contracara del modelo de cascada. Sigue un modelo de planificacin de objetivos, identificacin de riesgos y desarrollo y verificacin del producto en n iteraciones, esto lo convierte en adaptativo (contempla cambios acomodndolos en el plan de las sucesivas iteraciones). Tomamos prestada una fase del artculo donde sostiene la importancia de que el proceso no fuerce al diseador a tomar decisiones en forma anticipada: [The spiral approach] fosters the development of specifications that are not necessarily uniform, exhaustive, or formal, in that they defer detailed elaboration of low-risk software elements and avoid unnecesary breakage in their design until the high-risk elements of the design are stabilized. El modelo de espiral tiene un contenido altamente orientado al proceso (en el artculo no hay una sola mencin sobre el papel que juegan las personas dentro del proyecto) No podemos afirmar que sea una metodologa orientada al producto ni a la documentacin, en cada iteracin debemos armar el anlisis de riesgo, relevar los requerimientos de sistema y de software, hacer el plan de la iteracin siguiente, el diseo global y detallado y los casos de prueba, pero por otra parte tambin la iteracin contempla la posibilidad de prototipar y exige la presentacin de un software testeable para el usuario. Proceso unificado: comercializado por varias empresas, el proceso unificado es el primero que permite adaptarse segn el tamao del proyecto y su complejidad. Se autodefine como un proceso iterativo e incremental, dirigido por los casos de uso, orientado a la arquitectura y que busca anticipar los riesgos del proyecto. Las fases del proyecto se dividen en: Inception, Elaboration, Construction y Transition. Cada una es susceptible de dividirse en iteraciones y lo que diferencia una fase de otra es la madurez del producto que se est construyendo. Desde la fase de Elaboracin hay construccin, test y deploy de un ejecutable, por eso su naturaleza es iterativa. De la misma manera, se evita tomar decisiones en forma prematura y se contempla la posibilidad de modificar los requerimientos hasta la ltima iteracin, por lo que tambin encaja perfectamente en las metodologas adaptativas. UP sugiere una gran cantidad de artefactos de documentacin, aunque podemos minimizarlos para concentrarnos en el cdigo funcionando para el usuario. En la discusin filosfica documentacin vs. producto podemos decir que UP est a mitad de camino de ambas, como lo confirma esta frase: El producto no es slo el ejecutable, tambin es la documentacin que acompaa al sistema: manual de usuario, casos de uso, diagramas de clase, diagrama de arquitectura, etc. Respecto a la orientacin persona o proceso podemos decir que UP se mantiene en una zona gris. Por un lado define que las personas son importantes y tienen que saber qu hacer, mientras que al mismo tiempo cada persona cumple un rol que sugiere que esas personas estn supeditadas a un proceso en el cual confiar. Metodologas giles: como extreme Programming, Scrum (segn el artculo de Jeff Sutherland y Ken Schwaber, basado en el artculo original de Takeuchi, Hirotaka; Nonaka, Ikujiro), ASD, etc. Todas se basan en el manifiesto gil que establece sus principios metodolgicos para desarrollar software: Las personas y cmo se relacionan entre s son ms importantes que los procesos y las herramientas tecnolgicas (es orientado a las personas, por definicin) Un producto funcionando es ms importante que la documentacin exhaustiva (orientado al producto) La colaboracin del cliente es ms importante que la negociacin del contrato (que discrimina al cliente como parte externa del producto) Responder al cambio es ms importante que seguir el plan (adaptativo/iterativo) Links relacionados Volver a Diseo de Sistemas The New Methodology, artculo de Martin Fowler" + +} , + +{ + +"title" : "Java", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/java.html", +"date" : "", +"content" : "Sobre el lenguaje: Lambdas en Java 8 Java - Pgina oficial Java (Wikipedia) Oracle Technology Network for Java Developers(Algunas) Herramientas basadas en Java: JVM JDK Android SDK Eclipse IDE intelliJ IDE Apache Commons Google Guava Joda Time UI/Web Development Swing SWT GWT Wicket Play Framework Apache Tomcat Persistencia- [Hibernate](http://www.hibernate.org/)- [JDBC](http://en.wikipedia.org/wiki/Java_Database_Connectivity)SCM (Software Configuration Management)- Maven - [Apache Maven](http://maven.apache.org/) - [Maven (Wikipedia)](http://en.wikipedia.org/wiki/Apache_Maven)" + +} , + +{ + +"title" : "Javascript", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/javascript.html", +"date" : "", +"content" : "Sobre el lenguaje JavaScript (Wikipedia) Mozilla Developer NetworkHerramientas basadas en JavaScript La mayora de los web browsers modernos (Google Chrome, Mozilla Firefox, Opera, Safari) estn implementados usando JS. Adobe Acrobat, Reader, Dreamweaver, Photoshop, Illustrator, etc. Apache OpenOffice Google Apps Script Adobe AIR GNOME Shell JSON JQuery Node.js Ajax (tcnicamente no es una herramienta, sino un conjunto de tcnicas para desarrollo de aplicaciones web)" + +} , + +{ + +"title" : "JDK vs. JRE", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/jdkVsJre.html", +"date" : "", +"content" : "Cuando nos piden instalar Java (a secas) en nuestra mquina, es importante tener en claro la diferencia entre: JRE o Java Runtime Environment: un conjunto de herramientas que permite ejecutar cdigo compilado en Java. El environment o ambiente donde viven los objetos se implementa con la JVM (Java Virtual Machine). JDK o Java Development Kit: incluye al JRE y adems le agrega herramientas propias para desarrollar en Java: el compilador (javac), el generador de documentacin html para las clases (javadoc), el debugger (jdb), entre otros.Para tener el listado completo de las herramientas que trae OpenJDK, recomendamos ingresar a esta pgina.Arquitectura general del entorno JavaEn este diagrama vemos el proceso de desarrollo de un programa Java desde que lo escribimos hasta que se ejecuta en una mquina (nuestra o de un usuario). Para compilar el programa Java a un cdigo intermedio o bytecode necesitamos el ejecutable javac, que viene con el JDK. El archivo .class generado puede ser interpretado en cualquier otro sistema operativo, solo necesitamos tener el JRE adecuado. Ejecutamos entonces el programa java (o javaw en Windows) pasando como argumento nuestro archivo .class para que el bytecode sea interpretado al cdigo de la mquina.Eclipse integra todas estas herramientas de manera que cada vez que grabs un archivo Java realiza la compilacin para generar el .class y ejecutarlo desde el mismo entorno. Por eso Eclipse es un IDE, o Integrated Development Environment.Desarrollo en Kotlin/JVMHaciendo la aclaracin de que hay variantes de Kotlin que no necesitan la JDK (Kotlin Native o bien Kotlin/JS), en las materias Algoritmos 2, Algoritmos 3 y Programacin con Herramientas Modernas trabajamos con Kotlin/JVM que precisan instalarse la JDK.De esa manera cuando generamos nuestro archivo .kt con el cdigo fuente, el compilador automticamente genera el bytecode asociado (el .class, que est en la carpeta build/classes/kotlin) utilizando tanto el compilador de Kotlin como las herramientas que trae la JDK.Como estamos trabajando dentro de un IDE, este paso adicional es transparente para nosotros. Solo debemos tener en cuenta que adems del plugin de Kotlin, necesitaremos tener instalada una JDK para que el proceso de fondo convierta los archivos .kt a .class.Como resultado, nuestros programas pueden ejecutarse utilizando la mquina virtual de Java a partir de cualquier JRE.Links relacionados Volver al men principal del entorno Kotlin Pgina principal de Algoritmos 2" + +} , + +{ + +"title" : "json", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/json.html", +"date" : "", +"content" : "JSONIntroduccinJSON (JavaScript Object Notation) es un estndar para expresar estructuras de datos en un subset del lenguaje javascript. Se hizo popular en los ltimos tiempos como el estndar de formato para transferir informacin entre sistemas. El JSON es una estructura arbrea, donde cada objeto es un mapa o diccionario.Facebook, Twitter, Foursquare proveen una forma de acceder a su informacin (contactos, tweets, y lugares, respectivamente) que nos retorna la informacin en formato JSON. La idea es parecida a la idea de XML (asumiendo que ya conocen esta idea), pero menos verborrgico.Ejemplo de una personaEjemplo de una persona en formato JSON: Un objeto es un conjunto de clave-valor entre llaves. Las claves tienen nombres en strings (entre comillas) Los valores pueden ser strings o nmeros, o bien otras estructuras. telefonos tiene como valor una lista o array, que se escribe con literales corchetes. Y elementos separados por comas. mascota tiene como valor otro objeto JSON, que a su vez tiene sus propios atributos como clave-valor.{ "nombre": "Juan", "apellido": "Prez", "edad": 45, "telefonos": [ 47574933, 29298122, 88384831 ], "mascota": { "nombre": "Colita", "tipo": "perro" }}Material complementario Tutorial de JSON" + +} , + +{ + +"title" : "Juegos de estrategia", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/juegos-de-estrategia.html", +"date" : "", +"content" : "Modelo inicialSe desea modelar un juego de estrategia en el cual existen unidades que se pueden atacar las unas a las otras.Al atacar una unidad a otra, se compara el potencial ofensivo del atacante con el potencial defensivo del defensor. En caso que el primero sea mayor al segundo, la unidad atacada pierde tanta energa como la diferencia entre el potencial ofensivo y el defensivo involucrados. En otro caso, no ocurre nada.Por ejemplo, si un atacante con 30 de potencial ofensivo ataca a un defensor con 20 de potencial defensivo, este ltimo pierde 10 de energia.Hay tres tipos de unidades: Guerreros -&gt; Que pueden ser atacados o atacar. Tienen un potencial ofensivo especfico cada uno y tambin su propio potencial defensivo. Comienzan con 100 unidades de energa. Murallas -&gt; Que pueden ser atacados pero no atacar. Tienen un potencial defensivo que equivale a su energa sobre 20, con un mnimo que depende de cada muralla. Comienzan con 1000 unidades de energa. Misiles -&gt; Que no pueden ser atacados pero pueden atacar. Su potencial ofensivo equivale a 100 multiplicado por la cantidad de kg de explosivos que tenga, que es propia de cada misil.Problemas con Herencia SimpleAl intentar modelar este ejercicio con herencia simple, uno se encuentra con el problema de que no es posible separar en dos clases el comportamiento de Atacante y de Defensor, para luego hacer que Guerrero utilice ambos comportamientos. La herencia simple entonces no contribuye a una solucin aceptable y se debe entonces buscar soluciones alternativas como composicin que requieren una porcin importante de glue code.Resolucin con Mixins en RubyRequerimiento descansar" + +} , + +{ + +"title" : "Testeo unitario avanzado", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/kotest-testeo-unitario-avanzado.html", +"date" : "", +"content" : "Este artculo presenta algunas guas para desarrollar los casos de prueba, considerando que ya tienen una base de testeo unitario automatizado. Si ests buscando un apunte, te recomendamos el siguiente apunte de Testing.Por otra parte, aqu explicamos la mecnica utilizando Kotest como framework de testeo, si ests buscando una variante que siga los lineamientos de JUnit, pods ver esta pgina.EjemploUn sistema de seguros de automotor define en qu casos se puede pagar un siniestro: para los clientes normales, si no son morosos (la deuda debe ser 0) para las flotas de autos, se soporta una deuda de hasta $ 10.000 si el cliente tiene ms de 5 vehculos hasta $ 5.000 en caso contrarioDefiniendo los escenariosEn base al ejemplo anterior, podemos considerar los siguientes escenarios: un cliente normal moroso: si debe $ 1 $ 50.000 no nos importa, porque est en la misma clase de equivalencia una flota con menos de 5 autos ( 5 autos) =&gt; seran pocos autos una flota con ms de 5 autos =&gt; seran muchos autosElegimos cuntos autos en base al valor lmite: como a partir de los seis autos se considera mucho y menos de 6 son pocos autos, 6 es el valor de una flota con muchos autos, 5 es el valor de una flota con pocos autos.Estructura de los testsLa estructura que tienen los tests en base a los escenarios propuestos podra ser:dado un cliente normalque es moroso: no puede cobrar un siniestroque no es moroso: puede cobrar un siniestrodado un cliente de flota con muchos autos (6 autos)si el cliente debe ms de $ 10.000 no puede cobrar un siniestrosi el cliente debe $ 10.000 o menos, puede cobrar un siniestrodado un cliente de flota con pocos autos (5 autos)si el cliente debe ms de $ 5.000 no puede cobrar un siniestrosi el cliente debe $ 5.000 o menos puede cobrar un siniestroDefiniendo las especificaciones de los testsNecesitamos un cliente normal una flota de 6 autos otra flota de 5 autosa los que podemos configurar diferentes grados de deuda. Podemos seguir algunas recomendaciones adicionales:Agrupar los escenarios en diferentes archivosPor el momento, no tenemos demasiados requerimientos. Entonces vamos a trabajar los tres escenarios desde el mismo archivo, al que llamaremos CobroSiniestroSpec.kt para explicitar el caso de uso que estamos testeando.A la hora de disear nuestros tests, hay dos ideas que estn en tensin reutilizar nuestros escenarios, es decir, los objetos que estamos testeando que en cada test quede claro qu objetos participan de esa prueba (lo que se llama SUT, System Under Test)Por ejemplo, podramos tener una flota con 6 autos y hacer tests para diferentes casos de uso: el cobro de un siniestro, el valor mensual de la cuota, el horario de atencin, etc. El tema es que los tendremos en distintos archivos de test. La reutilizacin nos lleva a poner las cosas en un solo lugar, por ejemplo definiendo variables de instancia en una superclase comn (o cualquier mecanismo que aumenta el alcance de la variable, volvindola ms global). Todo eso dificulta el entendimiento posterior del test, porque el cdigo que se ejecuta previo a l est en varios lugares que adems no son fciles de rastrear. Ms abajo veremos qu tcnicas podemos utilizar para mantener nuestros tests simples.Cada uno de los escenarios se implementa con un describe diferente, entonces tendremos 3 describes: uno para clientes normales, otro para una flota con pocos autos y otro para una flota con muchos autosEs importante que no haya demasiados detalles de implementacin en la descripcin de los describes: dada una flota con 5 autos o data una flota con 6 autos provoca que cualquier cambio del negocio respecto a lo que son muchos o pocos autos necesite modificar esa descripcin: es una duplicidad difcil de detectar.Intention revealing - parte 1Queremos expresar lo ms claramente posible la intencin del describe: qu clase de equivalencia est testeando. Por eso comenzamos escribiendo:describe("Tests Cobro Siniestro") { describe("Dado un cliente normal") { ... describe("Dada una flota con muchos autos") { ...Los describes agrupan los tests e incluso se pueden anidar, aunque por simplicidad solo vamos a utilizar un describe raz para explicitar qu caso de uso estamos testeando. Una vez ms recordamos: muchos autos es mejor que decir 6 autos. En otras palabras, explicitar el caso de prueba y no el dato de prueba: 6 autos es un dato concreto, pero lo que representa es el caso de prueba de una flota con muchos autos.Expresividad en los testsUn primer approachPara crear nuestro fixture de una flota con muchos autos, los enunciados suelen traer ejemplos como: Lidia Pereyra tiene una flota con 6 autos. Es tentador escribir un test como el siguiente:describe("Lidia Pereyra") { val pereyra = Flota().apply { cantidadAutos = 6 } it("no puede cobrar siniestro") { pereyra.generarDeuda(10001) pereyra.puedeCobrarSiniestro() shouldBe false } ...}Pero qu pasa si hay un error en el cdigo de negocio? Supongamos esta implementacin, donde la clase Cliente tiene la definicin de la deuda como un entero:class Flota : Cliente() { var autos: Int = 0 override fun puedeCobrarSiniestro() = this.deuda &lt;= maximoPermitido() fun maximoPermitido() = if (autos &lt;= 5) 5000 else 20000 // debera ser 10000 en lugar de 20000}Cuando ejecutamos el test tenemos muy poca informacin relevante: la variable pereyra no est revelando que es un cliente de flota con muchos autos y tampoco est claro por qu no puede cobrar el siniestro el cliente.Al fallar la condicin tenemos que bucear en el cdigo y extraer este dato para determinar si el error est en el test o en el cdigo de negocio.Una segunda oportunidadVamos a mejorar la semntica del test, renombrando la variable pereyra por un nombre ms representativo de la clase de equivalencia que estamos modelando y cambiando la descripcin para el test:describe("Dada una flota con muchos autos") { val flotaConMuchosAutos = Flota() flotaConMuchosAutos.autos = 6 it("si tiene mucha deuda no puede cobrar siniestro") { flotaConMuchosAutos.generarDeuda(10001) flotaConMuchosAutos.puedeCobrarSiniestro() shouldBe false }Ahora al fallar el test sabemos ms cosas: el test con su stack trace, pero tambin qu es lo que estamos testeando, tratando de no entrar en detalles para no duplicar lo que dice el cdigoAAA PatternLos tests suelen estructurarse segn el patrn AAA: Arrange, Act y Assert.describe("Dada una flota con muchos autos") { // Arrange val flotaConMuchosAutos = crearFlota(6) it("si tiene mucha deuda no puede cobrar siniestro") { // Act flotaConMuchosAutos.generarDeuda(10001) // Assert flotaConMuchosAutos.puedeCobrarSiniestro() shouldBe false } it("si no tiene poca deuda puede cobrar siniestro") { // Act flotaConMuchosAutos.generarDeuda(10000) // Assert flotaConMuchosAutos.puedeCobrarSiniestro() shouldBe true }}ArrangeEn el Arrange: donde instanciamos los objetos a testear, con sus colaboradores: en el ejemplo son la flota y sus autos.Instanciar un objeto adecuado para el test puede involucrar varios pasos, en ese caso es conveniente definir mtodos helpers que adems puedan reutilizarse en diferentes contextos:fun crearFlota(cantidadAutos: Int) = Flota().apply { autos = cantidadAutos }... describe("Dada una flota con muchos autos") { // Arrange val flotaConMuchosAutos = crearFlota(6)En el ejemplo tenemos un mtodo helper del test que permite crear un objeto Flota pasndole la cantidad de autos a crear. De esa manera la configuracin de una flota ocurre en una sola lnea y se puede incluir dentro del test mismo. El nmero 6 representa el valor lmite para la flota, podramos setearlo en base a una constante asociado a la clase Flota:// clase Flotaval LIMITE_MUCHOS_AUTOS = 5// el testdescribe("Dada una flota con muchos autos") { // Arrange val flotaConMuchosAutos = crearFlota(LIMITE_MUCHOS_AUTOS + 1)La nica cuestin a tener en cuenta aqu es que est bueno que los tests tengan la mnima lgica posible, de manera de no estar repitiendo la misma lgica que ya tiene el negocio: la ventaja que tiene escribir crearFlota(6) es que si el lmite de lo que se considera muchos autos cambia, el test falla y eso puede ser til. Una heurstica posible sobre el setup del test es tratar de mantenerlo simple y de alto nivel, ms cercano al lenguaje del dominio que con detalles de implementacin. En el ejemplo de arriba se logra con mensajes que se encargan de instanciar objetos de dominio y que esconden la complejidad de conocer la colaboracin entre la flota y sus autos). Una alternativa a tener mtodos en el test puede ser crear un objeto especfico que construya otro objeto, algo que dejaremos para ms adelante.ActAct: son las operaciones que tienen efecto. En el caso de la flota que tiene una deuda abultada, enviamos el mensaje que le genera la deuda. Hay tests que quizs no necesiten disparar acciones, y est bien que eso ocurra.AssertEn el Assert indicamos qu esperamos que pase, generalmente asociado a las respuestas que da el envo de un mensaje al objeto testeado. Para esto utilizamos los matchers de Kotest.One assert per testHay ciertas controversias respecto a si podemos tener varios asserts en el mismo test, ya que cuando el primer assert falla los siguientes no se siguen evaluando: esto en realidad depende del runner de los tests, podramos eventualmente trabajar con un framework que continue buscando asserts y discrimine cules anduvieron y cules no (RSpec, framework de testeo para Ruby, hace sto).En verdad, la heurstica que nos interesa recomendar es: los tests deben fallar por exactamente un solo motivo, esto relaja esa restriccin. Lo importante no es tener un solo assert, sino que todos los asserts estn relacionados con la misma funcionalidad. Dejamos un ejemplo concreto:describe("Dado un parser de patentes de autos") { it("se obtiene correctamente la parte numrica de una patente vieja") { val lista = PatenteParser("ABC257").parsearNumeros() lista.size shouldBe 3 lista[0] shouldBe 2 lista[1] shouldBe 5 lista[2] shouldBe 7 }}El lector puede profundizar con estos artculos: Multiple Asserts Are OK Good Unit Test - One AssertTL;DREste es el resumen de buenas prcticas a la hora de definir tus tests: arm los escenarios que definen las clases de equivalencia de los tests escrib la descripcin de los describes y los tests explicando qu estamos testeando. El cmo lo termins de ver en el cdigo, evit duplicidades entre el texto que explica y el cdigo escrito separ los describes por requerimientos / casos de uso y los tests por escenarios donde quede claro la clase de equivalencia (cliente comn, flota, etc.) los nombres de las variables deben reflejar la clase de equivalencia que estn resolviendo, y no casos particulares que no revelan la intencin de lo que estamos modelando (s flotaConPocosAutos, no flotinha o miFlota) los tests se suelen estructurar utilizando las tres A: Arrange (el setup que conviene mantenerlo simple), Act (operaciones con efecto cuando corresponde) y Assert (las aserciones que deben testear el mismo concepto en cada test)Links relacionados Video en youtube que explica cobertura y clases de equivalencia en un proyecto Kotlin Si conocs Ruby, te recomendamos Better specs Pgina principal de Algoritmos 2" + +} , + +{ + +"title" : "Kotlin - control de versiones", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/kotlin-amigandonos-git.html", +"date" : "", +"content" : "Los archivos a versionar en GitNo todos los archivos deben subirse al repo. Como regla general no deberan subir archivos que se puedan generar a partir de otros, por ejemplo: los binarios que se generan a partir del cdigo fuente de ustedes (el directorio build). Ocupan espacio en el repositorio y se corre el riesgo de estar trabajando con versiones desactualizadas. archivos de configuracin propios de IntelliJ (el directorio .idea), que se pueden armar en base al build.gradle.kts cuando se importa el proyecto en nuestra mquina la primera vez. archivos que genera Gradle localmente (el directorio .gradle, distinto al gradle que es donde est el script ejecutable o wrapper). Si quers conocer ms en profundidad la estructura de las carpetas que utiliza Gradle, te recomendamos esta pgina.Archivos a ignorarDebemos crear un archivo .gitignore (que en Wollok se los cre el propio entorno), en la carpeta raz del proyecto, que debe tener al menos esta lista:HELP.md.gradlebuild/!gradle/wrapper/gradle-wrapper.jar!**/src/main/**/build/!**/src/test/**/build/### STS ###.apt_generated.classpath.factorypath.project.settings.springBeans.sts4-cachebin/!**/src/main/**/bin/!**/src/test/**/bin/### IntelliJ IDEA ###.idea*.iws*.iml*.iprout/!**/src/main/**/out/!**/src/test/**/out/### NetBeans ###/nbproject/private//nbbuild//dist//nbdist//.nb-gradle/### VS Code ###.vscode/Git por consola o Git con una herramienta visual?Da lo mismo, eleg la herramienta que mejor te resulte. El plugin de IntelliJ tiene un buen soporte para Git, aun as hay otras opciones (tens los links en la pgina), lo importante es cmo te organizs con tus compaeres.Recomendaciones para trabajar con mi grupoUn da en la vida de una persona que desarrolla (si van a trabajar en una rama sola) Cuando empiezo el da primero sincronizo el repositorio para ver los cambios que no tengo en el cdigo. Si no hay cambios, simplemente corro los tests y empiezo a codear como un campen. Si no Acepto los cambios entrantes y en caso de ser necesario resuelvo conflictos Corro los tests y veo que todo anda sobre ruedas Vuelvo a sincronizar y veo que ya no quedan ni conflictos ni cambios sin aceptar Subo mis cambios al repositorio remoto para que mis compaeros lo vean Ahora s, a programo, programo, programo y cuando termino, corro los tests Y vuelvo a sincronizar contra el repositorio remotoEn resumen: No pasa un da de trabajo sin hacer un commit y push al repositorio remoto. Esto implica planificar mi trabajo para que pueda subir algo al repositorio sin que rompa todo: hay que partir un cambio grande en pequeos pasos (iterativo, incremental). Nunca deberan subir nuevos fuentes al repositorio sin explicar brevemente qu cambiaron. Si los mensajes son descriptivos (y fix, asdsadsa o arreglo una cosita definitivamente no lo son) rpidamente puedo detectar qu modificaron mis compaeros con slo leer lo que escribieron en los commits. Una buena descripcin me ayuda tambin a entender qu es lo que se modific y por qu razn, especialmente til a la hora de solucionar un conflicto o entender por qu se rompieron los tests. El que rompe los tests paga las facturas.Y si cada uno trabaja en una rama separada? mejor, no voy a tener conflictos: eso no es cierto. Cada vez que integres tu cdigo en el branch principal se pueden romper tests o funcionalidades no puede pasar ms de 3 das sin abrir el PR (Pull Request), dejar pasar el tiempo hace que integrar tu cdigo sea un proceso largo y tedioso un TP no se puede entregar en 5 ramas distintas, tiene que haber una sola fuente de verdad y es la rama principal del repositorio remoto tener integracin continua es fundamental si queremos trabajar con ramasMetodologa para trabajar en grupo los tests tienen que estar en verde siempre los tests son de todos y todos somos responsables por mantenerlos si encontramos un bug y no haba un test que lo probaba agregamos uno los tests son rpidos de correr (no pueden tardar 10 minutos)Links tiles Siguiente paso: Gua rpida de Kotlin Volver al men principal del entorno Kotlin" + +} , + +{ + +"title" : "Bajar un proyecto Kotlin - Gradle de un repositorio git", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/kotlin-bajar-un-proyecto-gradle-de-un-repositorio-git.html", +"date" : "", +"content" : "DescripcinEste artculo asume la presencia de un entorno de trabajo Kotlin. En caso de que todava no tengas instaladas esas herramientas, te recomendamos leer estas instrucciones.Tambin se asume la preexistencia de un proyecto construido con Gradle y publicado en un repositorio Git, si lo que se desea es crear el proyecto en lugar de descargarlo, aqu estn las instrucciones para la creacin de un proyecto y su posterior publicacin en el repositorio.El proceso tiene los siguientes pasos, que se detallan a continuacin: Clonar el proyecto desde el repositorio remoto y alojarlo en nuestro espacio de trabajo local. Hacer el build del proyecto Kotlin en IntelliJ tomando como base las definiciones de Gradle.Descarga (clone)El checkout se puede hacer desde el IntelliJ o por consolaA continuacin explicaremos ambos pasos por separado.Por lnea de comandoPaso 1: clonacinPara esto debemos ubicarnos en el directorio de trabajo saber la URL del repositorio en el que se public el proyecto$ cd ~/workspace/materia # el directorio principal donde estn tus proyectos$ git clone https://github.com/uqbar-project/eg-microprocesador-kotlinEn el directorio local se bajan los recursos del proyecto, incluyendo un directorio .git donde est la informacin. De ser necesario debemos cambiar la rama o branch de trabajo, por ejemplo al branch dev:$ git checkout devPaso 2: Importacin del proyecto en IntelliJPara importar un proyecto en IntelliJ una vez descargado si tens un proyecto abierto, desde el men principal: File &gt; Open si no hay ningn proyecto abierto, el botn OpenNos puede aparecer una ventana de dilogo para que confiemos en el proyecto:Aceptamos seleccionando la opcin Trust project y entonces se importar el proyecto, al detectar que est hecho en Gradle se utilizar el archivo correspondiente para hacer el build. Te recomendamos que actives el check para que IntelliJ confe en todos los proyectos que te descargs en la carpeta raz de la materia.Y ya podemos comenzar a trabajar!Descarga desde IntelliJIntegracin de tu usuario de github (solo la primera vez)En caso de utilizar directamente el plugin de IntelliJ, te recomendamos integrar tu usuario de Github de la siguiente manera si tens un proyecto abierto, desde el men principal: Git &gt; Clone si no hay ningn proyecto abierto, el botn Get from VCSAparece esta ventana de dilogo, seleccionamos Github:Se abre una ventana de un navegador donde nos pide autorizacin para acceder a nuestra cuenta de github:Confirmamos qu cuenta de Github es la que vamos a integrary presionamos el botn Authorize JetBrains:Ingresamos la contrasea(si activaste la autenticacin en 2 pasos o 2FA es probable que tengas que ingresar tu token tambin).Una vez finalizado este paso ya podemos cerrar el navegador y volver a IntelliJ:Clonar un proyecto en IntelliJUna vez que tengamos asociado el usuario el proceso es muy sencillo, porque tendremos acceso a todos los repositoriosAqu podemos hacer una bsqueda y nos aparecern todos los repositorios a los que tenemos acceso. Por ltimo, solo debemos seleccionar el directorio donde vamos a bajar localmente nuestro proyecto para trabajar con el IDE y presionar el botn Clone. Nos puede aparecer una ventana de dilogo para que confiemos en el proyecto:Aceptamos seleccionando la opcin Trust project y entonces se importar el proyecto, al detectar que est hecho en Gradle se utilizar el archivo correspondiente para hacer el build. Te recomendamos que actives el check para que IntelliJ confe en todos los proyectos que te descargs en la carpeta raz de la materia.Si necesitamos movernos a otra rama, eso se puede hacer mediante la opcin Git &gt; Branches y seleccionando la rama que quieras + Checkout. Tambin tens la opcin de hacer click sobre la rama que se muestra en la parte inferior del IDE:Y ya podemos comenzar a trabajar!Links tiles Cmo trabajar con el control de versiones Cmo crear un proyecto Kotlin con Gradle Volver al men principal del entorno Kotlin" + +} , + +{ + +"title" : "Integración continua para materias con Kotlin", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/kotlin-ci.html", +"date" : "", +"content" : "Integracin continua (CI)DefinicinLa integracin continua busca automatizar los cambios en el cdigo que escriben varias personas en un proyecto de software. De esa manera facilita la experiencia de descargarse un proyecto y hacerlo funcionar localmente en nuestras mquinas permite la deteccin temprana de errores, cuando es ms fcil resolverlos.Qu necesitamos para implementarla en nuestro proyectoPara poder implementar la integracin continua, necesitamos la comunicacin entre las personas que desarrollan en el proyecto (es importante que se hablen entre ustedes) un servidor de integracin continua: Github Actions, CircleCI, Jenkins, etc. configurar nuestro proyecto contra ese servidor: eso puede involucrar uno o ms archivos una herramienta de versionado: git, Mercurial, etc. y sobre todo, una buena calidad de tests automatizadosEstrategia propuesta para proyectos con KotlinA continuacin vamos a describir los pasos necesarios para que tu proyecto Kotlin tenga integracin continuaServidor de integracin continuaEl servidor de integracin continua ser el que provee Github, y tiene las ventajas de estar integrado a tu repositorio y no tener que hacer nada para activarlo. Pods navegarlo en la solapa Actions:Configuracin del CI en el proyectoCopiate este archivo en la siguiente estructura que hay que crear&lt;directorio raz&gt;.githubworkflowsbuild.ymlQu pasa entoncesA partir de aqu, cada vez que: Hagas un push en las branches main o master Crees un PR que quiera mergear a main o master Hagas un push en las branches asociadas a uno de esos PR (mientras se encuentre abierto).En esas situaciones, Github Actions como servidor de integracin continua har lo siguiente de forma automtica: clonar tu repositorio lo compilar (build) en Kotlin mediante el script de Gradle ejecutar los tests en caso de error, mandar un mail avisando que el build fall (por el momento solo al autor del commit/PR) si anduvo ok, por defecto no recibirs ninguna notificacin si es un push directo, actualizar la badge de cobertura de JaCoCo en .github/badges/jacoco.svg s, en cambio, es un evento relacionado con un Pull Request no actualizar la badge, pero comentar en dicho PR con la cobertura actual luego de aplicar los cambios sugeridos. Finalmente, subir a la descripcin de esta instancia del action un artefacto con un reporte de cobertura generado por JaCoCo en HTML. Los artefactos son archivos que github permite almacenar, junto a logs, junto a un intento de build durante un periodo determinado de tiempo (actualmente un mximo de 90 das, tras lo cual son eliminados) Todo esto es muy til, ya que al automatizarlo no tendremos que acordarnos de hacerlo. Queda adems registrado si cada commit pasa o no, lo cual nos ayuda a encontrar donde se ubica el cdigo donde se origin el error.Agregando el Badge de Build al READMEEl badge es un indicador visual de cmo result el ltimo build, que ubicaremos en el archivo README. Para eso, ingresamos a nuestro repositorio, solapa Actions, elegimos cualquiera de los builds luego a la derecha hacemos click sobre el botn que tiene los tres puntos: ... en el men contextual elegimos la opcin Create Status Badge, elegimos la rama que queremos y presionamos el botn de copia. luego vamos al editor, pegamos el texto en el README y pusheamos al repositorio.Links tiles Video en youtube que explica cmo es la integracin continua con Kotlin y Github Actions Volver al men principal del entorno Kotlin" + +} , + +{ + +"title" : "Kotlin - Cómo generar un proyecto desde cero", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/kotlin-creacion-proyecto.html", +"date" : "", +"content" : "Para realizar las prcticas, vas a crear un proyecto desde cero. Como ahora hay muchas ms opciones, te dejamos una gua simple de cmo iniciarte.Crear proyecto KotlinDesde IntelliJ tenemos dos opciones: sin ningn proyecto abierto, nos aparece un botn New project o bien si tenemos un proyecto abierto, tenemos que abrir el men File &gt; New &gt; Project...Eso abre la siguiente ventana de dilogo: El nombre del proyecto no debe contener espacios ni caracteres especiales (IntelliJ te va a avisar) Todos los ejemplos que vas a descargar de la materia, as como los proyectos en los que vas a trabajar, se basan en la tecnologa Gradle. Asegurate que tengas seleccionada la opcin Gradle en Build System y Kotlin para la opcin Gradle DSL. Revisamos que la opcin en Project JDK por defecto sea la JDK 21, en caso contrario debemos ir a configurar la versin de Java Te recomendamos que el group id sea ar.edu.zzzz.xxx donde zzzz sea la universidad y xxx sea la materia que ests cursando. Por ejemplo ar.edu.unsam.algo2 para la materia Algoritmos 2 de UNSAM. Esta opcin est disponible si expands el grupo Advanced settings. El nombre del artefacto (Artifact ID) es el nombre de tu proyectoCuando finalizamos, se genera un proyecto con un archivo build.gradle.kts, que es fundamental para que IntelliJ lea esas definiciones para el proyecto en otra mquina y descargue las dependencias.Archivo de configuracin de GradleTe dejamos un archivo con las dependencias base para la cursada de Algoritmos 2 (UNSAM) del ao 2024: build.gradle.kts de ejemplo. Luego tendrs que renombrar el archivo a build.gradle.kts copiarlo al directorio raz de tu proyecto ya creado revisar el groupId para ver si es el adecuado revisar las dependencias para ver si es necesario agregar algn elemento msUna vez que actualicemos ese archivo, desde IntelliJ nos aparecern dos conos para indicarnos que debemos sincronizar las definiciones de Gradle con las de nuestro IDE:Al hacer click automticamente se actualizarn las dependencias. Este proceso es muy importante ya que de otra manera podremos experimentar problemas como imports que no funcionan, o mtodos que no se pueden encontrar (por estar usando versiones diferentes a las que queremos realmente).Continuous integrationPor el momento, lo que necesits es nicamente copiar este archivo en la siguiente estructura que hay que crear&lt;directorio raz&gt;.githubworkflowsbuild.ymlPara ms informacin pods consultar la pgina de integracin continua para proyectos en Kotlin.Primeros pasosVamos a crear nuestra primera clase Perro. Es importante notar que tendremos dos carpetas donde ubicaremos los fuentes: src/main/kotlin: donde irn las clases src/test/kotlin: donde irn los testsPor eso, nos ubicamos en src/main/kotlin y con un botn derecho, seleccionaremos New &gt; Kotlin Class/File.Shortcuts de IntelliJA continuacin te dejamos algunas recomendaciones para que tu estada en IntelliJ + Kotlin sea ms feliz: Cmo era para? Lo mejor es preguntarle al propio IDE, presionando dos veces Shift + Shift. Desde esa ventana de dilogo pods buscar cualquier palabra clave, como New, Save, Run, Select. Presionar dos veces Ctrl + Ctrl te permite ejecutar cualquier comando vlido desde el componente donde ests ubicado. Alt + Enter activa sugerencias tanto para errores como para cosas que se pueden mejorar (warnings).Presionando la tecla F2 te pods mover al siguiente lugar del archivo donde hay un error o warning: Nunca nos olvidemos de que nuestro cdigo tiene que ser entendible para el resto de la humanidad y lo mejor es pedirle al IDE que lo haga mediante Ctrl + Alt + L o bien con Ctrl + Alt + Shift + L (te abre una ventana de dilogo con ms opciones).Tip: si ests trabajando en una distribucin de Linux que utiliza KDE, el shortcut Ctrl + Alt + L es tomado por el sistema como la accin para bloquear la pantalla. Para desactivarlo segu estas instrucciones.La configuracin base se puede definir mediante File &gt; Settings y luego: Editor &gt; Code Style &gt; Kotlin, aunque te recomendamos que dejes los valores por defecto, as como recomendamos que todas las personas tengan la misma configuracin.Por ltimo, dos muy buenas opciones para seleccionar elementos son Ctrl + Alt + Shift + J: selecciona todas las ocurrencias de un elemento (para renombrarlo existe otro shortcut, Shift + F6) Alt + J: permite ir seleccionando elementos similares uno por uno.Otros comandos tiles: Ctrl + D: duplica una lnea Ctrl + Y: elimina una lneaSi ests trabajando con Mac los shortcuts son diferentes, en ese caso o bien para ms informacin pods ver este artculo.Packages para agrupar cdigo comn Utilizacin de packages (paquetes). Es una buena prctica agrupar las clases afines en paquetes para organizar semnticamente el cdigo. No hay una gua firme a seguir con respecto a cmo organizar nuestros archivos, ya que suele depender del contexto en el cual estamos trabajando, pero a medida que veas nuestros ejemplos y vayas haciendo las prcticas notars que hay clases que se pueden agrupar en contextos similares. Te dejamos un ejemploproyectohomeregistrationProfile.ktUser.ktsettingsCustomPrivacy.ktDefaultPrivacy.ktPrivacy.ktSetting.ktDe esta manera, logramos mayor granularidad en la organizacin de nuestras clases.___Links tiles Video en youtube que explica cmo crear un proyecto Kotlin desde cero Cmo trabajar con el control de versiones Cmo importar un proyecto Kotlin con Gradle Volver al men principal del entorno Kotlin" + +} , + +{ + +"title" : "Guia rapida de Kotlin", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/kotlin-guia-rapida.html", +"date" : "", +"content" : "La siguiente es una gua de syntactic sugars de Kotlin, algunos de los cuales trabajan conceptos ms profundos que veremos a lo largo de la materia.Definicin de una claseUna clase necesita un nombre, atributos a los cuales referencia y mtodos, definidos mediante el prefijo fun.val ENERGIA_MINIMA = 10class Ave { var energia = 0 fun volar() { energia = energia - 10 } fun comer(cuanto: Int) { energia = energia + (cuanto * 2) } fun esFeliz() = energia &gt; ENERGIA_MINIMA fun resetearEnergia() { energia = 0 }}Reglas generales para la clase podemos escribir mltiples clases en un archivo Kotlin la definicin de la clase se encierra entre llavesAtributos la variable ENERGIA_MINIMA se define como una constante y es referenciable dentro de cualquier clase que est dentro de ese archivo. Otra variante es definir atributos asociados a una clase especfica (ver companion object), suele usarse como constantes o valores que difcilmente cambien. la variable energia es una variable de instancia porque cada objeto Ave tiene su propio valor. las variables tienen un tipo que se infiere en base al valor: en el caso de la energia es un nmero (Int) porque se asocia al valor 0 aunque podemos explicitarla nosotros de la siguiente manera:var energia: Int = 0// la variable energia // tiene el tipo Int y el valor por defecto 0 Kotlin automticamente define getters y setters para la variable energia (no es necesario hacer nada, mientras no especifiquemos la visibilidad del atributo a privada, de la siguiente manera: private var energia = 0) La manera de invocar al getter es: objeto.atributo y la manera de invocar al setter es objeto.atributo = valor:pepita.energia = 100 // &lt;-- equivale a pepita.setEnergia(100)pepita.energia // &lt;-- equivale a pepita.getEnergia()Ojo! si bien parece que estamos accediendo dirctamente a la variable de instancia, no es as. Kotlin simplemente traduce esa sintaxis a la anterior. Es decir que en ambos casos estamos igualmente llamando al getter y al setter. Pueden probar definiendo la variable energia como privada y el IDE mostrar un mensaje de error Cannot access energia: it is private in Ave.Mtodos respecto a los mtodos, algunos producen efecto (volar y comer) y otros simplemente devuelven un valor (esFeliz). en el caso de los mtodos con efecto, se delimitan con llaves. Por defecto los mtodos que no devuelven nada no tienen ninguna anotacin de tipo, se dice que son void o Unit.fun volar() { energia = energia - 10 } los mtodos que solo devuelven valores y tienen una sola lnea se definen con el smbolo =:fun esFeliz() = energia &gt; ENERGIA_MINIMA tambin es posible definir un mtodo que devuelve un valor mediante las llaves, definiendo una anotacin de tipo para el mtodo:fun esFeliz(): Boolean { return energia &gt; ENERGIA_MINIMA}En este caso el tipo de retorno del mtodo es Boolean. Si el mtodo tiene varias lneas es necesario utilizar este formato en lugar del =.Referencias variables y valoresEn Kotlin, al igual que muchos otros lenguajes, se diferencian las referencias como Variables: son referencias que pueden inicializarse apuntando a un objeto, y luego reasignarse a otro:var unString = "Pepito"unString = "Otro String" Constantes: son referencias que nacen apuntando a un valor y no pueden ser modificadas para apuntar a otro objeto. Seran como constantes.val constante = "Constante"constante = "Otro" // &lt;----- NO COMPILA !Ojo! no confundir el hecho de que no se pueda modificar la referencia de la mutabilidad/inmutabilidad del objeto al que apunta. Puedo tener un val apuntando a un elemento que s mute.val perro = Perro()perro.nombre("Juan")perro = Perro() // &lt;----- NO COMPILA: no puedo modificar la referenciaperro.nombre("Carlos") // &lt;---- SI COMPILA y puedo mutar la referencia nombre de perroCundo debera usar val y cundo varPor defecto defin tus variables como val, a menos de que necesites modificar las referencias. Por ejemplo: la edad de una persona debera poder modificarse, en cuanto al nombre puede ser que no necesites modificarlo o s, eso depender de las reglas de negocio. El motivo principal es acotar el efecto en nuestros programas, mientras menor sea el efecto, ms fcil es controlar nuestro software, y ms fcil ser testearlo.Companion objectKotlin provee la posibilidad de definir un objeto companion dentro de una clase, que es global para todas sus instancias:class Ave { companion object { var ENERGIA_MINIMA = 100 fun subirEnergiaMinima(cuanto: Int) { ENERGIA_MINIMA += cuanto } fun crear() = Ave() } var energia = 0 fun esFeliz() = energia &gt; ENERGIA_MINIMA ... en lugar de definir la referencia ENERGIA_MINIMA como constante por fuera de la clase, la asociamos al companion object para manipular la energa mnima (como por ejemplo para subirla o bajarla en base a un valor), debemos hacerlo tambin dentro del companion y tambin ofrecemos un mtodo para crear un Ave, que por el momento solamente hace Ave(), pero el mecanismo de instanciacin podra tornarse ms complejo y el companion object es adecuado para tal fin.Todo lo que definimos en el companion object es accesible para atributos y mtodos de instancia (como por ejemplo el mtodo esFeliz). Desde otra clase, podemos invocar a la funcin que crea un ave de la siguiente manera:val ave = Ave.crear()Objetos singletonKotlin provee la capacidad de definir objetos:object Pepita { var energia = 100 fun volar(minutos: Int) { energia -= minutos * 2 + 10 } fun comer(gramos: Int) { energia += gramos * 4 }}fun main() { Pepita.energia = 150 Pepita.volar(5) Pepita.comer(2) System.out.println("La energia de pepita es ${Pepita.energia}") // "La energia de pepita es 88"}Pepita es una instancia que se puede acceder globalmente, representa una implementacin thread safe del Singleton que es ms trabajosa de implementar en Java (pods investigar ms en este artculo). Si trabajaste en Wollok (o Scala) el concepto es exactamente similar, solo que el nombre debe comenzar con mayscula.Tipos de datosStringsUn string se encierra entre dobles comillas, o bien podemos aprovechar para escribir un texto largo con triples comillas dobles (lo que nos permite incluso utilizar enters). Podemos interpolar referencias de Kotlin mediante $ o bien utilizar cdigo ejecutable usando ${zzz} donde zzz es cdigo Kotlin.class Cliente { var nombre = "Juan" // string simple fun saludo() = "Hola $nombre" // string simple interpolando una referencia // string con mltiples lneas interpolando cdigo Kotlin fun saludoFormal() = """ Bienvenido, ${nombre.trim()} a nuestra aplicacin. En breve nos contactaremos con ud. """}NmerosExisten muchos tipos de datos diferentes para nmeros: Int: es un nmero entero que admite negativos pero sin decimales Double, Float: son nmeros reales que admiten decimales pero con errores en las operaciones, es por ello que no debemos usarlo para operaciones sensibles (como transacciones bancarias o que requieran clculos exactos). Por qu? Por este cdigo que pods probar en este REPLfun main() { val a: Double = 0.02 val b: Double = 0.03 val c: Double = b - a System.out.println(c) // 0.009999999999999998} BigDecimal: es el tipo de dato que conviene utilizar ya que no produce errores de redondeo (permite trabajar con una cantidad exacta de decimales y truncarlos o redondearlos en caso de ser necesario)import java.math.BigDecimalfun main() { val a: BigDecimal = BigDecimal("0.02") val b: BigDecimal = BigDecimal("0.03") val c: BigDecimal = b - a System.out.println(c) // 0.01}Tanto Int, como Double como BigDecimal representan objetos a los que pods enviarle mensajes:fun main() { val numero: Double = 10.0 System.out.println(numero.inc()) // 11.0 System.out.println(numero.rem(3)) // 1.0}Para ms informacin pueden ver esta pgina.Colecciones mutables e inmutablesEn Kotlin, todas las colecciones vienen en dos sabores: mutables e inmutables. Las primeras soportan modificar sus elementos (agregar, quitar, actualizar), mientras que las segundas solo permiten acceder a sus elementos. Queda a criterio de quien programa cul utilizar en cada caso, prefiriendo desde este espacio las inmutables (porque algo que no se puede modificar es menos propenso a errores).Existen literales para definir listas, conjuntos y mapas (dictionaries):fun main() { // Lista inmutable val myList = listOf("Hello", "World") myList.size // ERROR, no puedo agregar un elemento a una lista inmutable // myList.add("Goodbye") // Lista mutable val myMutableList = mutableListOf("Hello", "World") myMutableList.add("Goodbye") System.out.println("${myMutableList[1]}") // "World" // Set inmutable val mySet = setOf("Hello", "World") // ERROR, no puedo agregar un elemento a un set inmutable // mySet.add("Goodbye") // Set mutable val myMutableSet = mutableSetOf("Hello", "World") myMutableSet.add("Goodbye") myMutableSet.add("Hello") // no tiene efecto porque ya hay un elemento "Hello" System.out.println("${myMutableSet.size}") // 3 // Mapa/Diccionario inmutable val myMap = mapOf("a" to 1 , "b" to 2) // ERROR, no puedo agregar un elemento a un set inmutable // myMap.set("c", 3) val myMutableMap = mutableMapOf("a" to 1 , "b" to 2) myMutableMap.set("c", 3) System.out.println("${myMutableMap.size}") // 3}Recordemos que listas: respetan el orden en el que se agregan (como una fila) y admiten duplicados. conjuntos: no tienen orden y tampoco admiten duplicados. Dos objetos son iguales en base a la definicin de equals() y hashCode(). mapas: son un conjunto de pares clave/valor. Se acceden por clave. Ojo : no hay que mezclar las ideas de val y var con la (in)mutabilidad de las colecciones. Por ejemplo, una coleccin inmutable podra estar referenciada con var, mientras que una mutable podra ser val.Para ms informacin recomendamos leer el apunte de la materia sobre Colecciones la pgina oficial de Kotlin sobre colecciones.Rangos con arraysEs posible generar un rango de nmeros:// Array de enteros con valores [0, 0, 0, 0, 0]val arrZeros = IntArray(5)// Array de enteros de tamao 5 con valores [42, 42, 42, 42, 42]val arrConstants = IntArray(5) { 42 }// Podemos utilizar una lambda para inicializar un array: [0, 1, 2, 3, 4]var arrLambda = IntArray(5) { it }// ... o [1, 2, 3, 4, 5]var arrLambda = IntArray(5) { it + 1 }Ms abajo explicamos definicin de bloques o lambdas.Inferencia de tiposKotlin cuenta con inferencia de tipos, lo que permite que exista chequeo de tipos pero que muchas veces no sea necesario definir los tipos de las expresionesVemos un ejemplo en vivo, mostrando cmo cambia la solapa Structure (disponible mediante Alt+ 7) cuando modificamos el cdigo:Volviendo a la inferencia de tipos, es fundamental poder contar con un lenguaje que tenga chequeo de tipos para detectar errores en forma temprana pero que no me obligue a definir los tipos todo el tiempo. La definicin de tipos es obligatoria cuando la definicin pueda resultar ambigua para Kotlin, por ejemplo cuando definas un mtodo que retorna un valor pero no lo anotes en la definicin:fun resetearEnergia() { energia = 0 return true // ERROR: la definicin del mtodo conflicta con este return}En ese caso el IDE te mostrar un error y lo pods solucionar fcilmente indicando el tipo del valor a retornar (o bien eliminando la instruccin return):Instanciacin y constructoresInstanciacin por defectoPara instanciar un objeto, Kotlin no utiliza la palabra new, simplemente se invoca mediante el nombre de la clase y parntesis:class Entrenador { val ave = Ave()Definiendo constructoresAdicionalmente, podemos definir parmetros en la construccin de una clase (lo que en otros lenguajes se conoce como constructor):class Ave(var energia: Int = 0) { ...}El valor por defecto indica que podemos crear un ave sin pasar parmetros, en cuyo caso el valor de su energa ser 0:val pepita = Ave() // un ave con energia = 0Pero tambin podemos pasar un valor:val pepita = Ave(energia = 150) // un ave con energia = 150Si en cambio no definimos un valor por defecto para energiaclass Ave(var energia: Int) { ...es obligatorio pasarle un valor para energa:val ave = Ave() // ERROR: No value passed for parameter 'energia'val ave = Ave(energia = 200) // OKConstructores secundariosPor lo general solo es necesario definir un constructor por defecto, pero en caso de que lo necesites te dejamos este artculo que explica cmo escribir constructores secundarios.Herencia y redefinicin de mtodosA continuacin vemos cmo definir Golondrina como subclase de Ave.open class Ave() { ... open fun esFeliz() = energia &lt; ENERGIA_MINIMA}class Golondrina : Ave() { override fun esFeliz() = true}Aqu vemos que Golondrina hereda de Ave, indicado mediante el smbolo : Golondrina debe llamar al constructor de Ave, que al no tener parmetros se indica por el momento con parntesis vacos: class Golondrina : Ave() Golondrina redefine el comportamiento de esFeliz, lo pisa, y esto requiere la palabra clave override, de lo contrario el IDE mostrar un mensaje de error Para que una clase pueda subclasificarse Kotlin obliga a utilizar la palabra clave open. Una segunda variante es que la clase sea abstracta en cuyo caso automticamente es abierta. La misma operatoria debe seguir un mtodo: debe marcarse con la palabra clave open (como en el caso esFeliz) para poder redefinirse en las subclases, a menos de que el mtodo sea abstracto. Esto es un poco burocrtico y extrao para el objetivo general que suele tener Kotlin, pero por el momento es as.Torcaza: This y superSi queremos definir una clase Torcaza que redefina el comportamiento de volar pero que adems delegue el comportamiento en la superclase, debemos utilizar la palabra clave super junto con el mensaje a enviar:class Torcaza : Ave() { var vecesQueVolo = 0 override fun volar() { super.volar() vecesQueVolo++ } }Como regla general solo deben utilizar super cuando no puedan utilizar this, como en este caso: de lo contrario entraran en loop infinito si invocaran a this.volar().Constructores delegadoSi la clase Ave se definiera de la siguiente manera:open class Ave(var energia: Int = 0) {eso no producira ningn cambio en las definiciones de Golondrina y Torcaza ya que en cada invocacin tomara el valor por defecto de energa:class Torcaza : Ave() { // considera energia = 0Ahora bien, si la definicin del constructor en Ave no tuviera valor por defecto:open class Ave(var energia: Int) {Entonces es necesario redefinir el constructor por defecto para Golondrina y Torcaza y pasarle ese valor al constructor de Ave. Esto se hace de la siguiente manera:class Golondrina(energia: Int) : Ave(energia) {Si bien esto puede convertirse en algo tedioso, veremos que el IDE nos simplifica bastante esta tarea, utilizando Alt + Enter para aceptar la sugerencia:Clases y mtodos abstractosPodemos definir a Ave como clase abstracta, esto producir que no podamos instanciar objetos Ave. Una clase abstracta puede definir solo la interfaz de un mtodo, lo que se conoce como mtodo abstracto. Veamos el siguiente ejemplo:En el ejemplo: primero definimos Ave como abstracta eso provoca que el compilador tire un error cuando queremos instanciar un Ave en la clase Ornitologo lo corregimos instanciando una Golondrina luego, queremos definir un mtodo abstracto: esFeliz. Para ello reemplazamos la definicin por una cscara que solo dice que esFeliz debe devolver un booleano. Dado que no hay cdigo Kotlin nos fuerza a definir el tipo de retorno del mtodo (y de sus parmetros) porque no puede inferirlo. todos los mtodos abstractos deben estar implementados en las subclases: el compilador nos avisa que falta la definicin de esFeliz() en Torcaza. Con un botn derecho Implement members pegamos la definicin copiada.y finalmente todo compila.Te dejamos el cdigo completo:val ENERGIA_MINIMA = 10abstract class Ave(var energia: Int) { open fun volar() { energia = energia - 10 } fun comer(cuanto: Int) { energia = energia + (cuanto * 2) } abstract fun esFeliz(): Boolean fun resetearEnergia() { energia = 0 }}class Golondrina(energia: Int) : Ave(energia) { override fun esFeliz() = true}class Torcaza(energia: Int) : Ave(energia) { var vecesQueVolo = 0 override fun volar() { super.volar() vecesQueVolo++ } override fun esFeliz() = energia &lt; ENERGIA_MINIMA}class Ornitologo { fun trabajar() { val ave = Golondrina(energia = 100) ave.comer(2) ave.volar() }}InterfacesLas interfaces son un mecanismo que permite definir un contrato, provisto por una serie de mtodos que pueden o no estar definidos. Por ejemplo, veamos la interfaz Flying que expresa el contrato para cualquier elemento que sepa volar:interface Flying { fun isHappy(): Boolean fun fly()}Esto implica que cualquier definicin que implemente la interfaz Flying debe poder responder a esos dos mensajes: isHappy() y fly(). Por ejemplo, la clase Bird, donde el smbolo : sirve tanto para marcar herencia como implementacin:interface Flying { fun fly() fun isHappy(): Boolean}// clase Bird implementa Flyingclass Bird(var energy: Int = 100) : Flying { fun eat(howMuch: Int) { energy = energy + (howMuch * 2) } fun resetEnergy() { energy = 0 } override fun fly() { energy = energy - 10 } override fun isHappy() = energy &gt; MIN_ENERGY}Cada mtodo implementado debe anotarse con el prefijo override para indicar que est implementando los mtodos que le pide su interfaz.Por qu Flying no se define como clase abstracta? Podramos, pero mientras que una clase solo tiene una superclase puede implementar varias interfaces a la vez. Supongamos que ahora definimos la interfaz Living para representar seres vivos:interface Living { var energy: Int fun eat(howMuch: Int)}Living define un atributo sin ningn valor concreto, ya que no puede definir un estado, a diferencia de la clase abstracta. Ahora Bird puede implementar ambas interfaces, para lo cual tiene que indicar que va a redefinir el atributo energy y todos los mtodos abstractos requeridos por las interfaces Flying y Living:// clase Bird implementa las interfaces Flying y Livingclass Bird(override var energy: Int = 100) : Flying, Living { override fun eat(howMuch: Int) { energy = energy + (howMuch * 2) } fun resetEnergy() { energy = 0 } override fun fly() { energy = energy - 10 } override fun isHappy() = energy &gt; MIN_ENERGY}Por ltimo, las interfaces permiten definir implementaciones para los mtodos, como podemos ver en este ejemplo completo:val MIN_ENERGY = 100interface Flying { fun fly() fun isHappy(): Boolean fun canFly() = !isHappy()}interface Living { var energy: Int fun eat(howMuch: Int) { energy = energy + (howMuch * 2) } fun resetEnergy() { energy = 0 }}class Bird(override var energy: Int = 100) : Flying, Living { override fun fly() { energy = energy - 10 } override fun isHappy() = energy &gt; MIN_ENERGY}Aqu vemos que cuando le preguntemos a un pjaro si puede volar, la definicin la tomar de la implementacin de Flying. Por otra parte cuando le pidamos a un pjaro que coma, lo har en base a la definicin de la interfaz Living. De todas maneras hay que estar seguro de que vamos a reutilizar en ms de un lugar cada una de nuestras definiciones para no caer en el sobrediseo. TIP: A la hora de reutilizar, una interface nos permite tomar definiciones de mltiples lugares aunque no permite definir un estado mientras que una superclase abstracta nos permite definir una sola vez nuestros atributos aunque solo podemos tener una superclase.BloquesUn bloque permite definir una porcin de cdigo, tambin llamada expresin lambda:val cuadrado = { num: Double -&gt; num.pow(2) }cuadrado.invoke(5.0) // 25En este caso cuadrado es un bloque que recibe como parmetro un nmero con decimales y devuelve el cuadrado de dicho nmero. Si queremos definir el tipo de dato de cuadrado podemos:val cuadrado: (Double) -&gt; Double = { num: Double -&gt; num.pow(2) }cuadrado.invoke(5.0) // 25En general un bloque en Kotlin tiene la siguiente sintaxis:{ parametro: Tipo, parametro2: Tipo2 -&gt; expresin a resolver }De esta manera podemos enviar bloques como parmetros, algo muy til para trabajar entre otras cosas con las colecciones (map, filter, fold, etc.)Variable implcita itDentro de una expresin lambda, it es la variable implcita del primer parmetro, por lo tanto todas estas expresiones son equivalentes:System.out.println(alumnos.filter { alumno: Alumno -&gt; alumno.estudioso() })System.out.println(alumnos.filter { it.estudioso() })Para ms informacin pueden consultar la pgina oficial de lambdas de Kotlin.Manejo de nulls100 veces no deboLos valores nulos son siempre un dolor de cabeza, Kotlin es uno de los primeros lenguajes orientados a objetos que nace con una estrategia para mitigarlos. En principio una referencia definida como String o Int no acepta valores nulos.Ok, entonces podramos pensar que una solucin es sacar el null explcito, y si como dijo Ivn Noble algunos errores son deliciosos, sin dudas uno es ste:Debemos inicializar la referencia, exacto! porque de otra manera lo que pasa es que arrastramos un String que puede ser null por todo nuestro cdigo, solo por no tomar la decisin de que ese valor nunca puede ser nulo.LateinitUna variante para resolver el problema es definir el atributo como lateinit:class Persona { lateinit var nombre: String fun tieneNombreLargo() = nombre.length &gt; 10}El efecto que provoca es que Kotlin confa en que nosotros vamos a definir siempre un valor para el nombre de cada persona antes de utilizarlo. Por ejemplo:fun main() { val pepe = Persona() pepe.nombre = "Pepe" System.out.println(pepe.tieneNombreLargo()) // false}Y no hay ningn inconveniente. Qu pasa si en cambio probamos con esta variante?fun main() { val pepe = Persona() System.out.println(pepe.tieneNombreLargo())}Kotlin se va a quejar de que nosotros le dijimos quedate tranquilo que yo me ocupo del nombre y result que el nombre qued sin inicializar:Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property nombre has not been initialized at Persona.getNombre (File.kt:2) at Persona.tieneNombreLargo (File.kt:3) at FileKt.main (File.kt:8)Ms adelante, cuando trabajemos con algunos frameworks como Spring, veremos que el modificador lateinit nos va a ser de mucha utilidad. Mientras tanto, cuando nosotros controlamos la inicializacin de las referencias para cada objeto, la mejor estrategia es definir un valor no-nulo por defecto:class Persona { var nombre: String = "" fun tieneNombreLargo() = nombre.length &gt; 10}Valores que aceptan nullPara aceptar valores null todos los tipos deben incorporar el sufijo ?, por ejemplo String?, Int?, etc.class Persona { var nombre: String? = null ...El inconveniente es que para saber si una persona tiene nombre largo, tenemos que considerar ahora si tiene un nombre nulo:Operador !!Una opcin es utilizar el operador !! sobre nombre, que implica nuevamente confiar en que el nombre no va a ser nulo:fun tieneNombreLargo() = nombre!!.length &gt; 10Esto implica que anulamos la validacin y nos puede pasar lo mismo que en otros lenguajes como Java: al enviar un mensaje a una referencia nula el programa explota en tiempo de ejecucin.Exception in thread "main" java.lang.NullPointerException at Persona.tieneNombreLargo (File.kt:3) at FileKt.main (File.kt:8) at FileKt.main (File.kt:-1) Elvis operatorParece un emoticn, pero ?: es un shortcut para utilizar un valor por defecto cuando una expresin pueda ser nula:fun tieneNombreLargo() = (nombre ?: "").length &gt; 10En este caso, si la referencia nombre no est inicializada, se toma en cuenta la segunda expresin (el string vaco).Null safe operatorTambin podemos resolver envos de mensajes a referencias que potencialmente podran ser nulas:class Alumno(var nombre: String = "") { fun estudioso() = ... fun felicitar() { ... }}fun main() { val alumnos = listOf(Alumno(nombre = "Valar"), Alumno(nombre = "Arya")) val estudioso = alumnos.find { it.estudioso() } System.out.println(estudioso?.nombre) // null estudioso?.felicitar()}Si estamos buscando informacin del primer alumne estudiose (o de algune) enviando el mensaje find a la coleccin puede pasar que la bsqueda no encuentre ningn elemento. En ese caso el operador ?. es equivalente a escribir:val estudioso = alumnos.find { it.estudioso() }System.out.println(if (estudioso === null) null else estudioso.nombre) // nullif (estudioso !== null) { estudioso.felicitar()}pero como vemos es bastante menos tedioso de escribir. De todas maneras cuando sea posible es una buena prctica evitar la manipulacin de tipos de datos con valores nulos, porque no siempre se puede resolver mgicamente con un ? cualquier operacin:Entonces el consejo que te dejamos es solo dejar valores que acepten nulls cuando el negocio realmente lo necesite. Por ejemplo: si un perro puede tener dueo o no, entonces el atributo puede ser nullable.Comparar referenciasTenemos dos formas de comparar referencias en Kotlin: Igualdad referencial: definido por el operador ===. ref1 === ref2 si ambas referencias apuntan al mismo objeto. Esto lo determina la VM y no se puede cambiar. Igualdad estructural: definido por el operador ==. ref1 == ref2 en base a la definicin del mtodo equals() en la clase a la que pertenece ref1.Tener especial atencin a los strings, ya que dos strings con el mismo contenido pueden ser iguales pero no idnticos, dependiendo de las estrategias de optimizacin de la VM. Vemos un ejemplo ilustrativo:fun main() { val nombre = "Ernesto" val nombre2 = "Ernesto ".trim() System.out.println(nombre == nombre2) // true, tienen el mismo contenido System.out.println(nombre === nombre2) // false, no son el mismo objeto} Tip: Siempre es conveniente utilizar ==, que adems se puede redefinir en nuestras clases / objetos.Features avanzadosExtension methodsUna de las herramientas ms poderosas consiste en definir extension methods. Supongamos que un negocio tiene un horario de apertura y de cierre y queremos saber, dada una hora, si est abierto.class Negocio { var horarioApertura: Int = 9 var horarioCierre: Int = 18 fun estaAbierto(horaActual: Int) = horaActual.between(horarioApertura, horarioCierre)}Por supuesto, no compila. No existe el mtodo between asociado a los enteros. Pero podemos definir un extension method en cualquier archivo:fun Int.between(from: Int, to: Int) = this in from..toSi definiste la extensin en otro paquete, lo imports como cualquier otra definicin:package otroPackageimport betweenclass Negocio { ...En resumen, un extension method permite que nosotros agreguemos comportamiento por afuera de la definicin de una clase como si estuviramos trabajando en ella, algo muy importante cuando la clase no podemos modificarla (como en el caso de Int, String), o bien cuando se est regenerando todo el tiempo (cuando tenemos un framework que genera cdigo para nosotros), sin contar que adems estamos respetando la idea de mensaje (y por consiguiente, la posibilidad de seguir trabajando con polimorfismo).Data classesKotlin provee el concepto de Data class para definir clases que sirven para modelar valores (value objects):data class Point(val x: Int, val y: Int) { // ... definiciones adicionales ...}fun main() { val punto = Point(2, 4) System.out.println(punto.x) // 2 System.out.println(punto) // Point(x=2, y=4) System.out.println(punto == Point(2, 4)) // true}Aqu vemos que el data class Point define un constructor con dos parmetros que a su vez definen las variables x e y los getters para x e y existen automticamente como x e y son val esto hace que nuestro objeto Point sea inmutable, si sumamos dos puntos obtenemos un nuevo punto (como pasa al concatenar los strings hola y mundo donde se obtiene un nuevo string holamundo o al sumar 2 + 3 el resultado es un nuevo nmero 5) si definimos x (o y) como var, Kotlin le agrega los setters correspondientes el mtodo toString de un data class que crea Kotlin es muy conveniente, permite mostrar tanto la clase como su estado interno (a comparacin del toString por defecto que tiene Object que muestra solo el nombre de la clase y un nmero interno en formato hexadecimal) y por ltimo tambin redefine el mtodo equals de manera de utilizar igualdad estructural: dos puntos son iguales si tienen la misma informacin, porque cuando modelamos value objects es frecuente crear objetos para representar ciertos datos y despus se descartan Tip: qu objetos son candidatos a modelarse con data class: un Mail, un domicilio, en general cuando estamos agrupando informacin que est junta pero que no es especfica de un dominio, la identidad no es importante como pasa cuando definimos objetos cliente, producto, etc.Operadores para procesar mltiples envos de mensajesOtro syntactic sugar muy interesante de Kotlin es la posibilidad de enviar mltiples mensajes al mismo objeto, mediante varios operadores: apply let with run alsoval ventaNacional = Venta().apply { cantidadKilos = 12 fechaVenta = LocalDate.now() parcela = parcela50 comprador = CompradorNacional()}De esta manera, todos los mensajes se apuntan al objeto que resulta de evaluar la expresin Venta(), y simplifica el envo de mensajes:ventaNacional.cantidadKilos = 12ventaNacional.fechaVenta = LocalDate.now()ventaNacional....Otras variantesLas scope functions let, also, run y with son similares pero tienen ligeras variaciones para lo que sea ms conveniente en cada caso:LetEl valor que le pasamos como parmetro se referencia como it y lo que devuelve es el resultado de toda la operacin:Venta().let { it.cantidadKilos * it.parcela.tamanio } // devuelve un nmeroWithEl valor que le pasamos como parmetro se referencia como this y lo que devuelve es el resultado de toda la operacin. Tambin es til para trabajar el ejemplo original de la creacin de una venta diciendo a este objeto enviale estos mensajes:val ventaNacional = Venta()with(ventaNacional) { cantidadKilos = 12 fechaVenta = LocalDate.now() parcela = parcela50 comprador = CompradorNacional()}Para ms informacin (como las scope functions run y also) pueden ver este artculoLinks relacionados Colecciones Intro a manejo de errores con excepciones Ejercicio del Monedero para ver cmo interactan la UI y el dominio a partir de errores del dominio y del sistema TestingLinks tiles Volver al men principal del entorno Kotlin" + +} , + +{ + +"title" : "Kotlin - Preparacion del entorno de desarrollo", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/kotlin-preparacion-de-un-entorno-de-desarrollo.html", +"date" : "", +"content" : "Instalacin baseGit Bash (slo para Windows)Para simplificar el uso de Git en entornos Windows, existe la herramienta Git Bash que pods descargar a partir de esta pgina, haciendo click en el link Download.Si ests en Mac o Linux, pods saltear este paso.JDK: Java Development KitPrimero instalaremos el compilador de Java.Ingresamos a una de las siguientes direcciones, y descargamos la JDK 21, que es la versin que manejamos desde 2024: (Recomendado) Adoptium Eclipse Temurin - JDK provisto por la Fundacin Eclipse, y con apoyo activo al proyecto de parte de multiples compaas como Microsoft y RedHat (entre otras). El cdigo se distribuye usando la licencia GPL con ciertas restricciones provista por Oracle. Amazon Corretto - Otra variante de JDK distribuida (y con soporte a largo plazo) por parte de Amazon. Si bien se encuentra optimizada para sus sistemas de AWS (Amazon Web Services), es una alternativa que funciona sin inconvenientes en sistemas tradicionales, para los que ofrece descargas.Pasos de instalacinUna vez descargado el binario en una carpeta (supongamos que es C:&#92;jdk21), hay que configurar dos variables de entorno de tu sistema operativo: JAVA_HOME: tiene que apuntar a C:&#92;jdk21) PATH: hay que incorporarle C:&#92;jdk21&#92;bin (cuidando de no borrar lo que ya est)Te dejamos un video que explica cmo hacerlo para Windows (el procedimiento es similar para MacOS / Linux)Chequeos posteriores a la instalacin Dentro de las variables de entorno de tu sistema operativo debe estar JAVA_HOME asignada. En Linux / Mac esto es env | grep JAVA_HOME, y en Windows SET JAVA_HOME. Si la variable no est seteada, eso significa que te salteaste un paso, lo mismo si la carpeta que muestra JAVA_HOME no es la que contiene la versin que vos descargaste. En ese caso volv al punto anterior y segu nuevamente las instrucciones para encontrar lo que est faltando. En una ventana de lnea de comandos, verificar la versin de java instalada con java -version, y el compilador mediante javac -version. En ambos casos mostrar la versin por defecto para tu mquina. Si no aparece la versin que descargaste, el sistema operativo asume por defecto otra instalacin, que podra ser incluso de una JRE (ver ms abajo). En ese caso, revis el link del punto anterior para ver qu puede estar faltando y repet los pasos.JDK s, JRE no IMPORTANTE: tens que instalar una JDK, no una JRE (Java Runtime Environment) que solo te permite ejecutar programas Java ya compilados. Para saber si tens una JDK, deberas ir al directorio de instalacin y en la carpeta bin debe estar un programa llamado javac, que es el compilador de Java.Si no tens ese programa, no vas a poder pasar tus objetos a cdigo ejecutable en el entorno Kotlin: la solucin es muy simple, descarg e instal una JDK. Para ms informacin te recomendamos esta pginaIntelliJ IDEANuestro entorno integrado de desarrollo (IDE) permite que en una misma herramienta editemos nuestro cdigo fuente, compilemos, hagamos pruebas, y muchas cosas ms. En Algoritmos 1 ya conociste otro IDE: Eclipse, modificado especialmente para soportar el lenguaje Wollok. Aqu utilizaremos IntelliJ IDEA que tiene muchas similitudes con Eclipse.Pasos de instalacinTens que descargarlo desde esta pgina y te va a ofrecer dos opciones: Ultimate: es la versin que recomendamos, para obtener una licencia pods enviar una solicitud con tu cuenta de UNSAM (debe terminar en @unsam.edu.ar ya que de esa manera se comprueba el origen educativo de la cuenta) siguiendo los pasos que cuenta esta pgina. Community: es la versin open-source que no tiene disponibles los plugins para Spring, herramienta que vemos en Algoritmos 3 y Programacin con Herramientas Modernas.Chequeos de instalacinUna vez que te descargaste el instalable, solo tens que elegir la ruta donde va a quedar el ejecutable (pods dejar la que te ofrece el instalador) chequear la opcin para que te aparezca el link al ejecutable IntelliJ (64-bit launcher) las otras opciones no son necesarias activarlasy finalmente presionar Next hasta terminar el asistente.Necesitars definir un espacio de trabajo o workspace, que es la carpeta donde vas a ubicar todos tus proyectos. Por defecto ese directorio es ~/IdeaProjects donde ~ es tu carpeta personal (como C:&#92;Users&#92;fernando o /home/fernando).Configuraciones adicionalesPor lo general no es necesario hacer nada ms, solo en algunos casos en los que notes que funciona lento, pods configurar el tamao de memoria de la Virtual Machine de Java mediante el men Help &gt; Custom VM Options. Esto abre un archivo de texto similar al siguiente-Xms128m-Xmx2048m-XX:ReservedCodeCacheSize=512m-XX:+UseConcMarkSweepGC-XX:SoftRefLRUPolicyMSPerMB=50-XX:CICompilerCount=2-XX:+HeapDumpOnOutOfMemoryError-XX:-OmitStackTraceInFastThrow-ea-Dsun.io.useCanonCaches=false-Djdk.http.auth.tunneling.disabledSchemes=""-Djdk.attach.allowAttachSelf=true-Djdk.module.illegalAccess.silent=true-Dkotlinx.coroutines.debug=off-Dsun.tools.attach.tmp.only=trueLos parmetros que tens que revisar son: la memoria inicial con la que levanta IntelliJ: Xms la memoria mxima que puede ser utilizada para IntelliJ, que corre en una Virtual Machine de Java propia: Xmx. Por defecto viene con 2GB y para las necesidades de la materia no deberas tener que subirlo, pero en todo caso charlalo con tu docente favorito. Este parmetro especfico puede alterarse ms sencillamente mediante el men Help &gt; Change Memory Settings Para ms informacin pods chequear esta pgina.Plugin KotestSolo necesitamos agregar un plugin para ejecutar los tests unitarios: Kotest. Para instalarlo pods ir a esta pgina y clickear el botn Install to IntelliJ xxx donde xxx es la versin ms reciente que hayas instalado.Alternativamente se puede instalar abriendo el men File &gt; Settings, abriendo la seccin Plugins &gt; Marketplace y buscando Kotest all.Plugins de temas (Themes)Si te interesa configurar un tema de tu inters, pods buscar plugins que contengan la palabra Theme en el Marketplace, como se describe en esta pgina. Luego podrs seleccionar el tema de tu preferencia.InlaysEn versiones recientes puede ser que te aparezca un inlay que muestra informacin sobre los autores del cdigo en el repositorio que ests trabajando, algo que puede resultar un poco molesto. Para deshabilitarlo, pods seguir los pasos que se explican a continuacin: Settings -&gt; Editor -&gt; Inlay Hints -&gt; Code vision y desactivar la opcin Code author. Luego cerr los archivos que tengas abierto y volvelos a abrir nuevamente.Actualizaciones automticasUna vez instalado IntelliJ, el sistema te avisa cuando hay actualizaciones. Nuestra recomendacin es que esperes para instalarlo a que finalice el cuatrimestre a menos de que ests teniendo un problema serio para trabajar en tu entorno y sepas que la actualizacin lo resuelve.Links tiles Siguiente paso: Creacin de un proyecto en Kotlin Volver al men principal del entorno Kotlin" + +} , + +{ + +"title" : "Kotlin - pagina principal", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/kotlin-principal.html", +"date" : "", +"content" : "A continuacin te vamos a dejar los pasos de instalacin del entorno Kotlin para las materias Algoritmos 2, Algoritmos 3 y Programacin con Herramientas Modernas. Segu metdicamente los puntos y no saltees las verificaciones para asegurarte que en tu mquina tengas todas las herramientas necesarias para trabajar. Instalacin del entorno base Recomendaciones para trabajar en la materia Cmo generar un proyecto Kotlin nuevo Cmo importar un proyecto Kotlin con Gradle desde Github Cmo testear con Kotest Sobre el control de versiones Gua de Gradle Integracin continua en proyectos Kotlin Ayudas para manejarte con el lenguaje Gua rpida de Kotlin Colecciones Intro a manejo de errores con excepciones Testing avanzado " + +} , + +{ + +"title" : "Lambdas en java 8", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/lambdas-en-java-8.html", +"date" : "", +"content" : "En la versin 8 del lenguaje Java se introduce una herramienta fundamental para cualquier lenguaje de programacin orientado a objetos y que era una de sus principales falencias: las expresiones lambda, tambin conocidas como bloques de cdigo o funciones annimas.Con ellas podemos implementar fcilmente mensajes de alto nivel de abstraccin, que reciben o devuelven bloques de cdigo y se comportan de forma parecida a las funciones de orden superior que podemos encontrar en el Paradigma Funcional.Dado que el lenguaje Java existi mucho tiempo sin presentar Lambdas (a partir de utilizar Clases Annimas), estas presentan caractersticas distintivas si las comparamos con los bloques de Ruby o Smalltalk, o las funciones annimas de Scala o C#.Uso bsicoEn una primera aproximacin, una lambda es cualquier objeto que implementa algunas de las siguientes interfaces: Function: una funcin que toma un slo argumento Predicate: una funcin que toma un slo argumento pero que devuelve exclusivamente booleanos Consumer: una funcin que toma un slo argumento y no devuelve nada, probablemente porque produce un efecto. Es decir, los Consumers normalmente NO son computaciones puras. Para otras variantes, ver: http://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.htmlSi queremos recibirlas por parmetro, debemos simplemente tipar al parmetro de nuestro mtodo con alguna de estas interfaces.Ejemplo:PersonaprimerPersonasQueCumple(Predicate&lt;Persona&gt;predicado){ for(Personapersona:personas) if(predicado.test(persona)) returnpersona; thrownewPersonaNoExisteException();}Para pasarlas por parmetro, la sintaxis es la siguiente:(TipoParametroparametro)-&gt;cuerpoque es anlogo al siguiente bloque en Smalltalk (recordar que en Smalltalk las variables no se tipan explcitamente):[:parametro|cuerpo]Ejemplo:primerPersonaQueCumple((Personap)-&gt;p.esMayorDeEdad())En muchos casos como el anterior tipo del parmetro puede ser obviado, cuando este puede ser inferido por el contexto:primerPersonaQueCumple(p-&gt;p.esMayorDeEdad())Referencias a mtodosSi el cuerpo del mtodo es el envo de un slo mensaje (como en el ejemplo anterior), entonces podemos usar una MethodReference:primerPersonaQueCumple(Persona::esMayorDeEdad)Interfaces de un slo mensajePor motivos de retrocompatibilidad, en realidad, cualquier interface que defina un slo mensaje puede ser usada con la sintaxis de lambda. Ejemplo:interfaceChequeadorDePersona{booleanchequear(Personap);}PersonaprimerPersonasQueCumple(ChequeadorDePersonapredicado){ for(Personapersona:personas) if(predicado.chequear(persona)) returnpersona; thrownewPersonaNoExisteException();}Y se usa exactamente igual. De todas formas, si no pensamos darle alguna semntica particular a nuestro bloque de cdigo, preferiremos usar normalente las interfaces estndar comentadas anteriormente.Colecciones en JavaUna de las principales utilidades de las lambdas es el manejo de colecciones. Java 8 incorpora mensajes a sus colecciones para poder transformarlas usando mensajes anlogos a las funciones de orden superior de Haskell: map, filter y reduce(fold), limit(take), entre otros: http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.htmlLa forma de trabajar siempre es la misma: cuando tengamos una colecciones, le enviaremos el mensaje stream() para obtener una secuencia potencialmente infinita (anloga a las listas de Haskell), al cual le podemos enviar mensajes para filtrar, mapear, etc. Cuando hayamos terminado, y si queremos reconvertir nuestro Stream a una coleccin (como una List, Set, o Collection), le enviaremos el mensaje collect, indicandole a que tipo de coleccin queremos convertirlo: collect(toList()) (anlogo al asOrderedCollection de ST) collect(toSet()) (anlogo al asSet de ST) entre otros. Ver http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.htmlEjemplo:List&lt;Persona&gt;personas=Arrays.asList(jose,pedro,maria,anabela);Set&lt;Persona&gt;nombresDeDocentesSinRepetidos=personas .stream() .filter( Persona::esDocente) .map(Persona::getNombre) .collect(toSet());Lo cual es anlogo al siguiente cdigo Smalltalk:personas:={jose.pedro.maria.anabela}nombresDeDocentesSinRepetidos:= ((personasselect:[:p|pesDocente])collect:[:p|pnombre])asSetOrdenarEl orden superior se puede aprovechar para ordenar colecciones en Java. Supongan que tienen:publicclassFoo{privateStringbar;privateintbaz;//ysusgettersyconstructor}Cuando quieran tener algo ordenado segn un criterio, antes o despus, necesitarn un Comparator: es un objeto que nos dice si un objeto es menor que otro (precede a otro, diran en discreta). La buena noticia es que normalmente no tendrn que declarar una clase que implemente esta interfaz, sino que podrn definirlo usando una lambda. Por ejemplo, si quieren crear una priorirty queue que est ordenada segn bar, pueden hacer:PriorityQueue&lt;Foo&gt;foos= newPriorityQueue&lt;&gt;((x,y)-&gt;x.getBar().compareTo(y.getBar()));En general ni siquiera es necesario hacer la comparacin a mano. Si quieren ordenar por una propiedad (como en este caso) pueden utilizar Comparator.comparing:PriorityQueue&lt;Foo&gt;foos= newPriorityQueue&lt;&gt;(Comparator.comparing(foo-&gt;foo.getBar()));o lo que es lo mismo:PriorityQueue&lt;Foo&gt;foos= newPriorityQueue&lt;&gt;(Comparator.comparing(Foo::getBar));Si tienen que ordenar por multiples propiedades, pueden utilizar el mensaje thenComparing. Ejemplo de creacin de un TreeSet que ordene segun bar y luego segun baz:Set&lt;Foo&gt;foos= newTreeSet&lt;&gt;( Comparator.comparing(Foo::getBar).thenComparing(Foo::getBaz) );Finalmente, si tienen que ordenar al revs del orden de precedencia, pueden usar el mensaje reversed. Por ejemplo, ac se est obteniendo un stream ordenado por baz, de mayor a menor:Arrays.asList(newFoo("hola",2), newFoo("hello",9)) .stream() .sorted(Comparator.comparing(Foo::getBaz).reversed());Para ms informacin, miren la documentacin de Comparator: http://docs.oracle.com/javase/8/docs/api/java/util/Comparator.htmlNombres alternativosA veces se referencia a las lambda de Java como closure. En trminos generales esto no es correcto, dado que son ideas diferentes: una lambda es una funcin que no tiene nombre, mientras una closure o cierre o clausura es una funcin que puede acceder a las variables disponibles en el contexto en que se la declar.Sin embargo en este lenguaje informalmente y en trminos prcticos ambos conceptos son intercambiables, ya que todas las lambdas encierra su contexto, y el unico tipo de closure que se puede tener es con una lambda.Como prueba de esto, histricamente, los frameworks de Java llamaban a la interfaz a ser implementada con una clase annima indistintamente como Closure, Function o Lambda.Ms informacinPara ms informacin consultar: http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html http://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html" + +} , + +{ + +"title" : "Lectura de un paper", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/lectura-de-un-paper.html", +"date" : "", +"content" : "Un Paper puede leerse con distintos niveles de profundidad, segn el inters que tengamos sobre el tema. Obviamente esto es una gua, no hace falta ser tajante al respecto:Profundidad 1Leemos el ttulo y/o el abstract. A veces al leer el ttulo ya sabemos si nos interesa o no el tema. A veces hace falta leer el abstract para saber si el contexto sobre el que se trabaj es aplicable a mi trabajo o no.Por ejemplo, si leo en el contexto que solucion un problema X para lenguajes funcionales con chequeo esttico de tipos, y yo busco soluciones para Smalltalk, probablemente no me sirva :).Profundidad 2Ok, le el abstract y pareci bueno. Leemos la introduccin, los problemas que se presentan, Related work y conclusiones. Con eso nos empapamos bastante en el tema sin entrar en detalles. Obviamente a partir de aca podemos decidir si nos interesa o no ver en detalle la solucin que propone el tipo. En caso que nos interese, podemos pasar a la profundidad 3.Profundidad 3Leemos todo, includa la solucin, discusin Ok, podemos saltearnos la implementacin, je." + +} , + +{ + +"title" : "Lenguajes del paradigma logico", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/lenguajes-del-paradigma-logico.html", +"date" : "", +"content" : "IconSi bien es un lenguaje basado en procedimientos, su ejecucin goal oriented posibilita un estilo de programacin que guarda bastantes similitudes con el paradigma lgico. Adems la posibilidad de contar con generators permite utilizar backtracking dentro de los procedimientos.Por otro lado tiene soporte para realizar aplicaciones con interfaces grficas. Tambin existe una versin denominada Jcon que permite un fcil integracin con Java.La pgina principal del lenguaje Icon es: https://www2.cs.arizona.edu/icon/ pero la introduccin ms clara la encontr en: http://en.wikipedia.org/wiki/Icon_programming_language" + +} , + +{ + +"title" : "Lenguajes especificos de dominio", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/lenguajes-especificos-de-dominio.html", +"date" : "", +"content" : "Este artculo est en construccin, tenemos por ahora algunos puntos de referencia solamente: En este post de Debasish Ghosh hay buenas ideas sobre cmo utilizar el lenguaje scala para construir DSLs [http://debasishg.blogspot.com/2008/04/external-dsls-made-easy-with-scala.html ] " + +} , + +{ + +"title" : "Lenguajes para centrales nucleares", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/lenguajes-para-centrales-nucleares.html", +"date" : "", +"content" : " REDIRECCIN Robustez de los lenguajes" + +} , + +{ + +"title" : "Lenguajes", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/lenguajes.html", +"date" : "", +"content" : "A continuacin mencionamos algunos lenguajes que siguen las ideas del paradigma orientado a objetos, y les dejamos algunos links y ejemplos para los curiosos. Smalltalk Self Java Objective C C++ Groovy RubyHbridosAlgunos lenguajes si bien implementan ciertas ideas del paradigma de objetos, tambin implementan abstracciones de otros paradigmas. Algunos de ellos son: Scala Python C# JavaScript Object Pascal" + +} , + +{ + +"title" : "Ley de demeter", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ley-de-demeter.html", +"date" : "", +"content" : "Usamos la ley de demeter siempre que es posible (que es la mayora de las veces), pueden consultarla ac, un resumen: You can play with yourself. You can play with your own toys (but you cant take them apart), You can play with toys that were given to you. And you can play with toys youve made yourself.You can play with yourselfEsto significa que podemos enviarnos mensajes a uno mismo:Wollok:object pepita { method graznar(){ self.gastarEnergia() } // ...}(self soy yo mismo, me envo el mensaje gastarEnergia())You can play with your own toys (but you cant take them apart)Esto significa que nuestros atributos estn para mandarles mensajes:Wollok:object pepita { var ciudadActual = bsAs method estasContenta(){ return ciudadActual.esGrande() } // ...}(ciudadActual es un atributo de pepita, al que se le enva el mensaje esGrande())Pero no est bueno meterme con su composicin interna:object pepita { var ciudadActual = bsAs method estasContenta(){ return ciudadActual.poblacion().size() &gt; 50000 //esto es incorrecto } // ...}(es incorrecto hablar con los objetos que le pido a los objetos que le pido a los objetos. Ya que eso es como desarmar a ciudadActual. Directamente debo pedirle lo que necesito, que es saber si es grande)You can play with toys that were given to youEsto significa que puedo hablar con los parmetros que me lleguenobject pepita { method queresIrA(otraCiudad){ return otraCiudad.esGrande() } // ...}(otraCiudad es un parmetro que me llega en este mtodo, por eso ahora mismo puedo hablarle y mandarle el mensaje esGrande())And you can play with toys youve made yourselfEsto significa que puedo hablar con los objetos que yo haya creado:object pepita { method anioActual{ return new Date().year() } // ...}(new Date() representa el da de hoy, que lo acabo de crear, y le mando el mensaje year())ResumenPuedo mandarles mensajes a self, a mis atributos, a lo que me llega por parmetro, y a los objetos que cre yo.Entonces, esto es incorrecto:object pepita { method queresIrA(){ return otraCiudad.esGrande() } // ...} porque de dnde sac la otraCiudad? No es un parmetro, no es un atributo.Nota sobre los WKOsHay muchos lenguajes que ofrecen puntos de acceso globales a ciertos objetos, con quienes tambin se puede hablar.Por ejemplo, en Smalltalk puedo hablar con las clases, que son objetos globales:#Golondrina&gt;&gt;ciudadNatal ^ Ciudad getInstance: 'BuenosAires'(Hablo con Ciudad, que es una clase, y le digo getInstance:, lo que me da una ciudad bien conocida)Y en Wollok existen los WKOs (well known objects), que permiten hablarles directamente sin conocerlos:object pepita { method enQueKMNaciste() { return buenosAires.kilometro() } // ...}(puedo hablar con buenosAires, aunque no sea ni un parmetro ni un atributo, ya que es un WKO)" + +} , + +{ + +"title" : "Libreria y framework", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/libreria-y-framework.html", +"date" : "", +"content" : "LibreraUna librera es un conjunto de funciones llamadas desde afuera por un cliente. Dentro del POO, esto es una clase que recibe un mensaje, lo ejecuta y devuelve luego el control al cliente. La instanciacin de una librera es relativamente sencilla.FrameworkEl framework representa una abstraccin de diseo y tiene un comportamiento en s mismo. No es solamente una clase, sino que es un conjunto de objetos que se relacionan para servir a un dominio especfico.La integracin con mi sistema se da de mltiples maneras a veces extiendo de una superclase propia del framework, o defino un objeto que respeta el contrato que pide el framework, o envo un mensaje a un objeto del frameworkpero es usual que el framework me pida luego cosas a m, no tengo control sobre el flujo de envo de mensajes.La instanciacin del framework no es tan sencilla, ya que requiere un conocimiento del mismo." + +} , + +{ + +"title" : "Lista de proyectos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/lista-de-proyectos.html", +"date" : "", +"content" : "" + +} , + +{ + +"title" : "Listas por comprension", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/listas-por-comprension.html", +"date" : "", +"content" : "Tal vez recuerden de matemtica que se pueden definir conjuntos por extensin (por ejemplo {1,2,5,9}) o por comprensin ({X &#92; X Enteros ^ X &gt; 3 ^ X &lt; 15} ). La forma por extensin ya la vimos con en Haskell con las listas [1,2,5,9] y por comprensin podemos definirla mediante filtros y transformaciones (filter y map) sobre otra lista que sera el conjunto base.Las listas por comprensin en Haskell son un azcar sintctico que nos permite armar listas a partir de los elementos de otra luego de aplicar filtros y transformaciones, o sea, permiten escribir de una forma simple y elegante expresiones que podran ser ms complejas utilizando las funciones que ya conocemos para este fin.Veamos un ejemplo simple usando filter y map:nombresDeAlumnosQueAprobaron=mapnombre.filteraproboEsta funcin puede tambin escribirse con una lista por comprensin:nombresDeAlumnosQueAprobaronalumnos=[nombrealumno|alumno&lt;-alumnos,aproboalumno]Una diferencia que podemos notar entre ambas definiciones es la cantidad de parmetros a la izquierda del igual, en el segundo caso hay uno, mientras que en el primero no hay. Por qu pasa eso?Eso pasa porquemapnombre.filteraproboes una funcin ya que es la composicin de dos funciones.En cambio[nombrealumno|alumno&lt;-alumnos,aproboalumno]es una lista, esa es una diferencia importante y es un criterio que nos va a permitir saber cundo nos conviene usar map y filter en lugar de listas por comprensin.Otra cosa que agregan las listas por comprensin es la posibilidad de hacer pattern matching quedando an ms expresivo:[nombre|(nombre,nota)&lt;-alumnos,nota&gt;4]Otro ejemplo si tengo una lista de remeras de la forma:modelos=[("GoodIdeaBadIdea","flex",2,"negro"),...]A partir de esa lista podemos construir otra usando listas por comprensin y pattern matching:[(nombre,color)|(nombre,_,cant,color)&lt;-modelos,cant&gt;2]Aqu se puede ver la verdadera potencia de las listas por comprensin vs. map y filter, la posibilidad de utilizar el pattern matching.En resumen: Las listas por comprensin nos dan funcionalidades similares a las del map y filter, entonces es probable que en muchas situaciones se presenten como soluciones alternativas a un mismo problema. Las listas por comprensin permiten aprovechar mejor el pattern matching, entonces en los casos donde pueda usar esa caracterstica probablemente sea ms piola usar listas por comprensin en lugar de map y filter. Con listas por comprensin yo siempre defino una lista, mientras que combinando map y filter con aplicacin parcial yo puedo definir funciones, eso los hace ms aptos para la composicin, por lo tanto en los casos en que yo necesite componer (o trabajar al nivel de funcin por cualquier otro motivo, puede resultar ms adecuado usar map, filter, aplicacin parcial, composicin, etc." + +} , + +{ + +"title" : "Locro", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/locro.html", +"date" : "", +"content" : "Nuestra mega receta para 30 personas:Para el locro: 2kg Maiz Blanco 1Kg de Porotos 2kg de Rost beef 2kg de Bondiola 2kg de Pechito de cerdo y Patitas 1kg de Panceta 5 Chorizos colorados 4kg de ZapalloPara la salsa: 3 Cebollas Aj molido c/n 1/2 kg Grasa Comino c/n Pimentn c/nReceta original 1" + +} , + +{ + +"title" : "Logico trabajo con valores", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/logico---trabajo-con-valores.html", +"date" : "", +"content" : "Cundo se usa isCuando tengo que hacer una operacin aritmtica, p.ej..ingresoTotal(Pers,IT):-ingresoPorSueldo(Pers,IS),ingresoPorRenta(Pers,IR),ITisIS+IR.en este caso, la cuenta es una suma, debo usar is.Si lo de la izquierda es un valor, o una variable ligada con un valor, entonces el is se verifica si el resultado de la cuenta es el valor. P.ej. si quiero saber si juan tiene exactamente el doble de ingreso que roque, puedo hacer esta consulta?-ingresoTotal(juan,IngrJuan),ingresoTotal(roque,IngrRoque),IngrJuanisIngrRoque*2.No est bien usar el is cuando lo de la derecha no es una cuenta. Ms detalles a continuacin.Si s qu valor es, pongo el valorSi en un programa quiero representar bart es hijo de homero, pongo?hijo(X,Y):-X=bart,Y=homero.o pongohijo(bart,homero).Est claro que pongo lo segundo. Por qu? Porque no quiero decir X e Y son hijo y padre si a X le pasa tal cosa y a Y le pasa tal otra, sino que ya s quines son los que quiero relacionar, bart y homero.En todos (todos) los casos en los que ya s el valor, lo correcto es poner el valor, no hace falta pasar por una variable (como sera la variable X para bart en el ejemplo de arriba). Algunos ejemplos menos obvios. Estoy haciendo un programa que modela gustos en propiedades de la gente, donde a cada propiedad la modelo con un tomo que describe su direccin (p.ej. lavalle851). Tengo estas reglas A los que viven en Belgrano le gustan los departamentos lujosos. A Roque le gustan los departamentos chiquitos. A los que viven en Boedo les gusta el departamento de Corrientes 3804.En la primera regla slo me dan condiciones sobre persona y depto:gusta(Pers,Depto):-vive(Pers,belgrano),esLujoso(Depto).En la segunda, no me estn hablando de una persona cualquiera, me estn hablando de Roque. Entonces el primer argumento no necesita ser una variablegusta(roque,Depto):-esChiquito(Depto).Para la tercera, del que me estn hablando especficamente es del depto, de la persona me dan condiciones. Entoncesgusta(Pers,corrientes3804):-vive(Pers,boedo). En el mismo programa, quiero decir que un departamento es alternativa para otro si sale exactamente 5000 pesos menos. En este caso tengo que hacer una cuenta que es la diferencia entre los precios; s que el resultado de esa cuenta tiene que ser exactamente 5000.Entonces, pongoesAlternativa(Depto1,Depto2):-precio(Depto1,Pr1),precio(Depto2,Pr2),DifisPr2-Pr1,Dif=5000.oesAlternativa(Depto1,Depto2):-precio(Depto1,Pr1),precio(Depto2,Pr2),DifisPr2-Pr1,Difis5000.? Noooooo, el 5000 ya lo s, no necesito pasarlo por la variable Dif. O seaesAlternativa(Depto1,Depto2):-precio(Depto1,Pr1),precio(Depto2,Pr2),5000isPr2-Pr1." + +} , + +{ + +"title" : "Lombardizacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/lombardizacion.html", +"date" : "", +"content" : "Dcese de aquella actitud donde una propuesta viene siempre acompaada de un compromiso de accin. Es decir, una persona lombardizada es aquella que cuando hace una propuesta, se compromete a que esa propuesta se lleve a cabo. La Lombardizacin acepta como compromiso diversas actitudes que incluyen desde llevarlo a cabo completamente uno mismo hasta el movilizar gente para hacerlo.El trmino Lombardizacin proviene de la palabra Lombardi, tambien conocida como apellido de Carlono, en honor a Carlos Carlono Gran Vikingo Lombardi, perteneciente a este grupo. El orgen del uso de este vocablo se debe aLa Lombardizacin se ha extendido durante aos en muchos grupos de personas. El tpico grito de guerra con el que estas personas extienden estas creencias es Lombardizate!Ejemplos de LombardizacinHablando de escribir una entrada en la wiki:No Lombardizado: Deberamos tener una pgina en la wiki que explique la Lombardizacin a los mas nuevitos.Lombardizado: Che, escrib esta pgina en la wiki que explica la Lombardizacin para los mas nuevitos.Para conseguir alguien que de una clase:No Lombardizado: Che, hay que dar la clase de polimorfismoLombardizado: Che, puedo ayudar a dar la clase de polimorfismo? No me animo a darla soloMisconcepciones ComunesLa lombardizacin no significa: eh, gato, por qu en lugar de chamuyar no te pons a hacer algo, gil!Originalmente no era esa la idea. Lombardizacin es lo que en los crculos de la chetez empresarial se llama empowerment (pfff). Aplica cuando alguien viene con una idea pero su idea no pasa de eso, de una propuesta, entonces lombardizate significa: si tens una buena idea, no esperes a que otro la lleve a cabo o a que un comit de notables le de su bendicin, empujala vos, hacelo. Frecuentemente eso pasaba con los ms jvenes o recin llegados al grupo, que tal vez por no conocer la mecnica interna esperaba que las decisiones las tomaran los ms viejos y no se animaba a tener ms iniciativa. Entonces lombardizar es justamente hacer que este grupo funcione sin depender de uno que centraliza o que toma decisiones o que no se puede hacer nada sin tener su visto bueno." + +} , + +{ + +"title" : "Macros en Scala", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/macros-scala.html", +"date" : "", +"content" : "IntroduccinMacros es una herramienta muy poderosa que permite definir reescrituras de AST (Abstract Syntax Tree) y est presente en muchos lenguajes y tecnologas. A grandes razgos, la tilidad de las macros consiste en tomar una construccin sintctica vlida y reemplazarla por otra en tiempo de compilacin, permitiendo as que la sintaxis que normalmente construira un cierto programa construya otro totalmente diferente. En Scala, la utilizacin de macros est definida en el paquetescala.language.experimental.macrosel cual debe ser importado para poder trabajar.Una macro de Scala se compone de dos partes: Una declaracin y una implementacin. Al momento de compilar, los usos de la funcin declaracin son procesados para reemplazarlos por el resultado de aplicar la funcin implementacin. Definir la declaracin de una macro es muy similar a definir una funcin comn pero, en lugar del cuerpo, se utiliza la palabra clave macro seguida del nombre de la funcin implementacin. // declaracin def miMacro(parametro1: String, parametro2: Int) = macro miMacro_impl // implementacin def miMacro_impl(c: Context)(parametro1: c.Expr[String], parametro2: c.Expr[Int]) = ???Whitebox y Blackbox macrosExisten 2 tipos de macros, las llamadas de caja blanca o whitebox y las de caja negra o blackbox. La diferencia entre los dos enfoques es que las macros de caja negra se usan cuando puedo definir claramente una firma para la funcin que quieroimplementar usando macros, mientras que las de caja blanca se usan cuando no puedo definir dicha firma. Las macros de caja blanca son ms flexibles pero menos seguras, ya que no pueden tiparse y van a ser discontinuadas en versiones futuras de Scala, por esa razn vamos a concentrarnos en las definiciones de caja negra.Para elegir uno de estos dos enfoques es necesario importar el paquete correspondienteimport scala.reflect.macros.whiteboxpara las de caja blanca yimport scala.reflect.macros.blackboxpara las de caja negra.La clase Context que se us en el cdigo anterior est definida en estos paquetes.Mirando el ejemplo, se puede ver que hay una relacin entre el tipo de la declaracin de la macro y su implementacin que, adems de recibir un parmetro Context, espera tambin un parmetro por cada parmetro de la declaracin que debe tener el mismo nombre y un tipo de expresin que coincida. creado a partir del contexto.UsosVeremos que hay varias maneras de colgarse del proceso de compilador, por lo que tenemos distintos tipos de macros propuestos por scala, solo que en este caso nos estaremos enfocando en uno de los tipos de macros. Otra consideracin a tener en cuenta es que la interfaz que tenemos de macros como la de reflection en scala puede ir variando en el tiempo, ya que son an implementaciones experimentales y no se ha llegado a un estado final de como sera la implementacin definitiva.Las macros han sido utilizados durante la versin 2.10 de Scala, tanto para aplicaciones de investigacin como industriales, y la conclusin segn (Burmako), es que las macros han sido tiles para aplicaciones tales como: Code Generation Implementation of DSLs Static checking among othersMas informacinVer ms en detalle sobre macros en scala 2.10 en el siguiente link Bibliografa Burmako, Eugene. Scala Macros: Let Our Powers Combine! On How Rich Syntax and Static Types Work with Metaprogramming." + +} , + +{ + +"title" : "Manejo de booleanos en haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/manejo-de-booleanos-en-haskell.html", +"date" : "", +"content" : "El Tipo BoolLos booleanos son datos que representan la condicin de verdad o falsedad.Recordemos que even es una funcin que recibe un nmero, y devuelve un booleano. (True si el nmero es par)Hagamos estas consultas en la consola (El simbolito &gt; al inicio de la lnea indica que se est haciendo una consulta):&gt;even6True&gt;notTrueFalse&gt;notFalseTrueAqu se ve que not es una funcin recibe un Bool (y que devuelve el booleano opuesto).Hay otras funciones que devuelven booleanos:&gt;5&lt;1True&gt;"mama"=="papa"FalseEntonces, si queremos que una funcin devuelva un booleano, basta con devolver el mismo resultado que obtuvimos. Por ejemplo,--"lagolondrinapepitaestempachadasisuenergaesmayorque100"estaEmpachadaenergia=energia&gt;100Conjuncin y Disjuncin Lgica&gt;True||FalseTrue&gt;True&amp;&amp;FalseFalsePara saber si el 6 es par y divisible por 3:&gt;even6&amp;&amp;(esDivisible63)TrueErrores Comunestrue vs true vs TrueEn Haskell, true es un nombre de variable de funcin. Si trato de usarlo, me va a tirar el error Not in Scope.&gt;nottrue``Notinscope:`true'`` true es un String, por lo que si se lo mando a una funcin que espera un booleano, va a haber un error de tipos:&gt;not"true"`` Couldn'tmatchexpectedtype`Bool' ```` withactualtype`[Char]' `` True es la manera correcta de referirse al booleano. True es un Constructor del tipo de dato Bool.&gt;notTrueFalseProblemas con Booleanos y Guardas En Funciones_por_Partes#Errores_Comunes hay algunos errores comunes.Mal Uso de Booleanos (algo == True, etc.)Una variante de los problemas con Guardas es lo siguiente:desaprueba nota= estaAprobadanota== FalsepierdePromocion nota = estaAprobada nota == True &amp;&amp; nota &lt; 8Ese cdigo est mal. Por qu? Porque estaAprobada ya devuelve un Booleano. De la misma manera la funcin menor tambin devuelve un Booleano. Entonces, en el caso de pierdePromocion, est dems la comparacin por True. Y en el caso del desaprobada, si lo que necesito es el opuesto del booleano, entonces debo usar la funcin not:desaprueba nota= not (estaAprobadanota)pierdePromocion nota = estaAprobada nota &amp;&amp; nota &lt; 8Ese cdigo es el correcto. Comprobamos as que funcionan igual:&gt;estaAprobada7==TrueTrue&gt;estaAprobada 7True&gt;estaAprobada3==FalseTrue&gt;not (estaAprobada3)TrueAdems, algo muy importante, es ms expresivo usar el not, ya que se lee: desaprueba una nota cuando no est aprobada desaprueba nota= not (estaAprobadanota) .Y por ltimo, estoy ocultando un poquito el cmo . Es decir, nos concentramos en la idea de negacin, ms que en comparar booleanos por ==True o ==False. Como dice Fidel, un profe de la Universidad Nacional de Quilmes: No le tengamos miedo al booleano!" + +} , + +{ + +"title" : "Manejo de booleanos en smalltalk", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/manejo-de-booleanos-en-smalltalk.html", +"date" : "", +"content" : "Los Booleanos como objetosLos booleanos son objetos que representan la condicin de verdad falsedad.Recordemos que even es un mensaje que entienden los nmeros, y devuelve un booleano. (true si el nmero es par)6even."devuelvetrue"truenot."devuelvefalse"falsenot."devuelvetrue"Aqu se ve que not es un mensaje que entienden los booleanos (y que devuelve el booleano opuesto).Hay otros mensajes que devuelven booleanos:5&lt;1"devuelvefalse"1between:0and:3"devuelvetrue"Entonces, si queremos que un mtodo devuelva un booleano, basta con devolver el mismo resultado que obtuvimos. Por ejemplo,"lagolondrinapepitaestempachadasisuenergaesmayorque100"&gt;&gt;estasEmpachada^energia&gt;100.Conjuncin y Disjuncin Lgicatrue|false"devuelvetrue"true&amp;false"devuelvefalse"Para saber si el 6 es par y divisible por 3:6even&amp;(6isDivisibleBy:3)"devuelvetrue"Agregando VitaminasAdems de los mensajes binarios &amp; y |, tenemos los mensajes and: y or:, que en vez de recibir un booleano, reciben un bloque de cdigo (que adentro tiene un booleano). Veamos:6even|5even"devuelvetrue"6evenor:[5even]."devuelvetrue"5even&amp;6even."devuelvefalse"5evenand:[6even]."devuelvefalse"Para qu queremos estos mensajes? Porque son lazy. Es decir, tienen algo de evaluacin perezosa. sto significa que si estoy haciendo un or y el receptor ya es verdadero, no hace falta analizar el segundo elemento (el or es verdadero):5&gt;1or:[7*2]."devuelvetrue,sinanalizarelbloquebasura"5&gt;1|(7*2)."tiraerror,porque14noesunbooleano"Y si estoy haciendo un and y el receptor es falso, no hace falta analizar el segundo elemento (el and es falso):5evenand:[4]."devuelvefalse,sinanalizarelbloquebasura"5even&amp;4."tiraerror,porque4noesunbooleano"En general, es buena prctica utilizar and: y or:.Para pensarQu pasara en cada caso si dentro del bloque hay una operacin con efecto sobre el estado del sistema? La respuesta a sta pregunta nos va a ayudar a entender por qu no est bueno tener efecto cuando hacemos un and: un or:.Errores Comunestrue vs TrueEn el ambiente hay un objeto llamado true y otro llamado True.El que representa el valor de verdad, el s, es el true con minscula.True es la clase de la cual true es instancia. Lo que empieza en mayscula es casi-casi siempre nombre de clase (o de variable de clase, eso lo vemos cerca del final de la parte de objetos).Si uno se confunde y usa True, claro, el ifTrue: no anda bien, porque el mensaje ifTrue: lo entiende el objeto true, no su clase.ifTrue: [^true], est bien? Miremos este mtodo que est en una clase cuyas instancias entienden el mensaje paismismoPaisCon:unaCiudad((selfpais)=(unaCiudadpais))ifTrue:[^true]ifFalse:[^false]y supongamos que la comparacin((selfpais)=(unaCiudadpais))da true.Qu quiere decir que da true? Que si evalo esa parte, el objeto que me devuelve es el objeto true, el nico objeto true de Smalltalk. A ese le estoy diciendo ifTrue:ifFalse:, y en el bloque que ejecuta si es true le digo que devuelva true, o sea que devuelva el mismo objeto al que le dije ifTrue:ifFalse:. Lo mismo con el false.En resumen, el ifTrue:ifFalse: sobra, este mtodo se puede escribir asmismoPaisCon:unaCiudad^(selfpais)=(unaCiudadpais)y listo.=== ^(algo = true) === Una variante del caso anterior es un cdigo como este, dentro de una clase cuyas instancias entienden los mensajes estaLibre y estaAndandopuedeUsarse^(selfestaLibre=true)&amp;(selfestaAndando=true)Analicemos la parte(selfestaLibre=true)La expresin self estaLibre hace lo nico que puede hacer una expresin en Smalltalk: devolver un objeto. Qu objeto puede ser ese?1.Si la condicin es cierta, entonces el objeto que devuelve es el objeto true, el nico objeto en un ambiente Smalltalk que representa el valor de verdad cierto. Si a ese objeto le pregunto = true, qu objeto va a ser el resultado?Si pregunto si dos objetos son iguales, o me va a responder true, o me va responder false, no hay otra. En este caso, true es el mismo objeto que true, o sea el = da cierto, o sea devuelve true!, que es el mismo objeto que obtena con(selfestaLibre)2.Ahora supongamos que la condicin no es cierta, en ese caso me devuelve el objeto false, si a false le digo = true el resultado de eso es el objeto false, que otra vez es lo mismo que obtengo poniendo solamente(selfestaLibre)ConsecuenciaEl mismo anlisis lo puedo hacer con(selfestaAndando=true)y la conclusin es que el mtodo puede escribirse aspuedeUsarse^(selfestaLibre)&amp;(selfestaAndando)En esta versin estamos manejando mejor los booleanos, porque aceptamos que el resultado de self estaLibre es un booleano, que va a ser true o false, y que va a entender &amp; con el otro booleano como parmetro.Un caso parecidoY si en lugar de estaLibre tengo estaOcupado, qu hago, pongopuedeUsarse^(selfestaOcupado=false)&amp;(selfestaAndando=true)nooooo quiero el booleano contrario al resultado de self estaLibre, para eso los booleanos entienden not, en este casopuedeUsarse^(selfestaOcupadonot)&amp;(selfestaAndando)" + +} , + +{ + +"title" : "Manejo de booleanos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/manejo-de-booleanos.html", +"date" : "", +"content" : " Manejo de booleanos en Haskell Para el Paradigma Funcional Manejo de booleanos en Smalltalk Para el Paradigma de Objetos" + +} , + +{ + +"title" : "Manejo de errores", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/manejo-de-errores.html", +"date" : "", +"content" : " REDIRECCIN Excepciones" + +} , + +{ + +"title" : "Manejo de memoria en c", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/manejo-de-memoria-en-c.html", +"date" : "", +"content" : "https://github.com/jwise/minilib" + +} , + +{ + +"title" : "Maquina virtual", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/maquina-virtual.html", +"date" : "", +"content" : "Puede haber un poco de confusin con la palabra Mquina Virtual (VM).La imagen de Pharo corre sobre una mquina virtual, llamada Pharo VM o Squeak VM o Cog VM. Esta VM es un programa ms o menos comn y corriente, sobre el cual se carga una imagen de Pharo. Esta VM es indispensable.Mas all de que existe una diferencia tcnica enorme, en una primera aproximacin pods comparar a la VM de Pharo con el intrprete de Hugs o swi-prolog: son programas responsables de ejecutar tu cdigo. Luego, pods comparar a la imgen de Pharo con los archivos .pl o .hs: contienen cdigo y datos de tu programa.Por otro lado, en el laboratorio de sistemas, la VM de Pharo est instalada directamente sobre el sistema operativo (un Windows), mientras que los interpretes de Haskell y Prolog estn instalados, por cuestiones prcticas para la gente del laboratorio, en un sistema operativo virtualizado montado sobre una VM VMware, pero bien podran haberlo instalado sobre el mismo Windows.Esta ltima VM (VMWare) es de naturaleza totalmente distinta a la VM de Pharo: emula un hardware completo, y se la conoce como Mquina Virtual de Sistema. La mquina virtual de Pharo, en cambio, emula slo algunos algunos aspectos del hardware, y tiene como nica finalidad correr cdigo en Smalltalk. Se la conoce como Mquina Virtual de Aplicacin (en azul):Recalco que la virtualizacin en amarillo es totalmente opcional, en el labo est as porque ayuda a organizar el software para cada materia, pero normalmente en tu casa no vas a necesitar hacer eso para instalar el software de PDP." + +} , + +{ + +"title" : "Masa de pizza", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/masa-de-pizza.html", +"date" : "", +"content" : "Cantidad: 4 pizzasIngredientes: 1kg harina 000 o ms ceros 50 gr levadura sal, 4 cucharadas de aceite salsa de tomatePasos: Diluir la levadura con un poquito de agua, una cucharada de azucar, una cucharada de harina, dejarla espumar (que se haga una esponja). Si despus de un rato no esponja NO SIRVE. Tiene que quedar del mismo color. Poner la harina en bol cacerola o palangana, hacer un hueco en el centro agregar 3 cucharadas de aceite (o 4) y una cucharada de sal alrededor (sobre la corona). Poner la levadura sobre el aceite, agregar agua (medio litro de agua, de a poco) y mezclar, de adentro hacia afuera. Amasarla, golpearla hasta que quede blandita uniforma y que no se pegue en los dedos (o muy poquito). Se pone en un bol, se tapa y se deja descansar. Hasta que esta el doble de su tamao original (aproximadamente 20-30 minutos). NO PONER EN CORRIENTE DE AIRE. Volver a masar, sacarle bien el gas. Separar en bollos. Aceitar los moldes. Estirar la masa en los moldes con la mano aceitada para que no se pegue. Si dejamos los bollos hay que taparlos bien con papel film Cuando esta bien estirada ponerle muy poquitito de salsa (para que no se humedezca). Dejar leudar hasta que vuelva a duplicar su volumen. Poner en el horno bien caliente. Cuando hace piso, se le pone toda las cosas locas." + +} , + +{ + +"title" : "Introducción a Maven", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/maven.html", +"date" : "", +"content" : "Maven es una herramienta que ayuda a desarrollar un proyecto basado en el entorno de una JDK (Java, Xtend, Scala, Groovy, etc.)FuncionalidadesMaven cumple con las siguientes funciones principales que vamos a explicar en las siguientes secciones: Reificacin de Proyecto / Artefacto en forma standard, declarativa y extensible Manejo de Dependencias Manejo del Ciclo de Vida del Artefacto, incluyendo releasesReificacin de Proyecto/ArtefactoJava no trabaja la idea de proyecto, no lo representa como concepto. Entonces, cada uno de los IDEs pensados para Java agregan su propia forma de definirlo: en el caso de Eclipse tenemos el archivo .classpath que define los directorios donde compilar y las dependencias que necesita el archivo .project que contiene el nombre del proyecto, entre otras cosasSi nosotros trabajamos con otro IDE (como IntelliJ IDEA o NetBeans) tenemos que adaptar estos archivos para generar el proyecto con sus dependencias adecuadamente. Maven permite trabajar entre IDEs con su propio modelo de proyecto, que se guarda en el archivo pom.xml (de Project Object Model)Identificacin de un proyecto MavenEn el archivo pom se declaran, entre otras cosas, un identificador nico de nuestro proyecto/artefacto, que resulta de la unin de tres identificadores: groupId: representa la organizacin autora/duea del artefacto. Por ejemplo, los proyectos de Algoritmos 2 suelen usar el groupId org.uqbar. artifactId: este campo define el nombre por el que se conoce al proyecto en s mismo. Algunos ejemplos: commons-collections, eg-seguros-xtend, tp-futbol5-grupo01, etc. versin: es el ltimo componente del rompecabezas, dado que groupId:artifactId denota un nico proyecto pero no alcanza para definir en qu versin del proyecto nos estamos parando. Se agrega entonces un nmero de versin para completar la informacin que Maven necesita para generar una identificacin unvoca. Conviene seguir las reglas de versionado semntico, para liberar versiones productivas. A veces se suele acompaar de un sufijo RELEASE (para versiones estables) o SNAPSHOT (para versiones intermedias que pueden estar sujetas a cambios)A continuacin un ejemplo bsico.&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt; &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt; &lt;groupId&gt;org.uqbar&lt;/groupId&gt; &lt;artifactId&gt;uqbar-commons&lt;/artifactId&gt; &lt;version&gt;1.1.2&lt;/version&gt;&lt;/project&gt; Cuando se publica un componente, se empaquetan todas las clases compiladas (.class) en un archivo comprimido que tiene la extensin .jar (de Java Archive). Opcionalmente podemos tener un archivo comprimido extra con los fuentes.Repositorios MavenUn repositorio Maven es un lugar donde estn los artefactos Maven, estructurados en cierta forma estndar para hacer las descargas de las dependencias. Cuando instalamos Maven, se crea un repositorio Maven local en una carpeta que por defecto suele ser HOME/.m2. Si queremos ubicar al componente cuyo identificador es org.eclipse.xtend:org.eclipse.xtend.core:2.21.0.M1 podremos encontrarlo localmente en%M2_HOME%/repositoryorg eclipse xtend org.eclipse.xtend.core 2.19.0 (otra versin) 2.21.0.M1 --&gt; dentro de esta carpeta estar el .jar recordemos que el identificador de un componente se arma a partir del groupId + el artifactId + la versin se suele exportar como variable la carpeta HOME/.m2 con el nombre M2_HOME en M2_HOME puede haber opcionalmente un archivo settings.xml que veremos ms adelante en la subcarpeta repository estn todos los componentes que descargamos localmenteVemos un video de ejemplo, en una mquina Linux. El comportamiento en una mquina Windows es exactamente igual, hay que explorar los directorios incluyendo los que son ocultos, y navegar a partir de la carpeta de usuario.m2:Relacionando proyectos maven desde el POMEs posible referenciar a otros proyectos maven desde un POM, esto es muy til para cuando necesitamos declarar dependencias, definir un proyecto padre, agregar pluginsa la hora de compilar nuestro proyecto.DependenciasLas dependencias se definen dentro de un tag &lt;dependencies&gt;:&lt;project ...&gt; &lt;...&gt; &lt;dependencies&gt; &lt;dependency&gt; &lt;groupId&gt;org.junit.jupiter&lt;/groupId&gt; &lt;artifactId&gt;junit-jupiter-params&lt;/artifactId&gt; &lt;version&gt;5.5.2&lt;/version&gt; &lt;scope&gt;test&lt;/scope&gt; &lt;/dependency&gt; &lt;/dependencies&gt;En este caso, estamos definiendo que nuestro proyecto tiene como pre-requisito el componente junit-jupiter-params asociado a org.junit.jupiter. Si utilizamos Maven como un plugin de Eclipse agregamos la dependencia en el pom, actualizamos el proyecto (Maven &gt; Update project) y eso dispara la descarga del componente al repositorio Maven local como vemos en el videoAl agregar una dependencia a un proyecto es posible especificar el type (por ej., jar), el scope (por ejemplo: test), y si es o no optional.Parent projectOtra variante es utilizar un proyecto padre mediante el tag &lt;parent&gt;, como ocurra en versiones anteriores de los ejemplos de Uqbar hasta 2019:&lt;parent&gt; &lt;groupId&gt;org.uqbar-project&lt;/groupId&gt; &lt;artifactId&gt;uqbar-xtend-parent&lt;/artifactId&gt; &lt;version&gt;2.17.1&lt;/version&gt;&lt;/parent&gt;El parent project permite reutilizar definiciones comunes entre varios proyectos. En este caso particular, uqbar-xtend-parent (el nombre que le dimos a este artefacto) sirve para definir que utilizaremos la versin 2.17.0 de Xtend con una dependencia para correr tests unitarios compilando a JDK 1.8PluginsLos plugins de Maven no solo permiten reutilizar lgica sino que adems ejecutan acciones cuando son descargados. As funciona el ncleo central de Maven: uno de los plugins ms conocidos es clean, que elimina el directorio de destino (en el caso de Xtend, donde estn los archivos Java y los .class que se generan a partir de los fuentes originales). Otro plugin conocido es Surefire, que ejecuta los tests de un proyecto basado en JDK.Distintos proyectos maven requieren/ofrecen distintos settings al ser referenciados como plugins. Veamos un ejemplo de la configuracin del plugin de xtend: &lt;plugins&gt; &lt;plugin&gt; &lt;groupId&gt;org.eclipse.xtend&lt;/groupId&gt; &lt;artifactId&gt;xtend-maven-plugin&lt;/artifactId&gt; &lt;version&gt;2.20.0&lt;/version&gt; &lt;executions&gt; &lt;execution&gt; &lt;goals&gt; &lt;goal&gt;compile&lt;/goal&gt; &lt;goal&gt;testCompile&lt;/goal&gt; &lt;/goals&gt; &lt;configuration&gt; &lt;outputDirectory&gt;${project.build.directory}/xtend-gen/main&lt;/outputDirectory&gt; &lt;testOutputDirectory&gt;${project.build.directory}/xtend-gen/test&lt;/testOutputDirectory&gt; &lt;/configuration&gt; &lt;/execution&gt; &lt;/executions&gt; &lt;/plugin&gt; &lt;/plugins&gt;Aqu le estamos indicando a maven las caractersticas de la ejecucin del plugin, es decir: los goals (metas/capacidades del plugin). Este es un plugin de compilacin por lo que indica los valores compile y testCompile. la configuracin de las rutas del filesystem para los archivos java compilados.Lo recomendable en cada caso es siempre revisar la documentacin oficial del proyecto maven que queremos referenciar, para entender qu settings son requeridos o convenientes para nuestro proyecto.Dependencias transitivasUn detalle no menor de la resolucin de dependencias de maven es que tambin funciona para las dependencias transitivas.Por ejemplo: proyectoA &gt; proyectoB proyectoB &gt; proyectoC proyectoC &gt; proyectoD, proyectoE, proyectoFAl resolver las dependencias, el proyectoA necesitar descargar los componentes B, C, D, E y F. Incluso podramos requerir diferentes versiones de los mismos componentes.Noten que un proyecto comercial normal o mediano, puede incluir decenas y hasta cientos de dependencias. Eclipse permite integrar todas las definiciones de un pom junto con sus parents en la solapa Effective POM:Repositorios remotosLa pregunta que puede hacerse el lector es: desde dnde se descargan los componentes la primera vez? Cmo es que Maven sabe dnde ubicarlos, y cmo saber a qu versin apuntar? Por defecto, Maven apunta a un repositorio central donde se suben todos los componentes que utiliza la comunidad que trabaja con la JDK: https://repo.maven.apache.org/maven2/Cuando tenemos dudas sobre las versiones de algn componente, podemos hacer una bsqueda enhttp://search.maven.orgpor ejemplo, podemos buscar el componente uqbar-domain, que direcciona a https://search.maven.org/search?q=uqbar-domain. All tenemos todos los releases, con sus fechas correspondientes:Para publicar un componente en el repositorio Sonatype que est relacionado con Maven Central, hay que cumplir algunas reglas. En particular, para los componentes Uqbar hay que seguir estas instrucciones.Definiendo repositorios remotosEn nuestro pom.xml podemos definir repositorios adicionales donde encontrar componentes de Maven:&lt;project&gt; ... &lt;repositories&gt; &lt;repository&gt; &lt;id&gt;my-internal-site&lt;/id&gt; &lt;url&gt;http://myserver/repo&lt;/url&gt; &lt;/repository&gt; &lt;/repositories&gt; ...&lt;/project&gt;Otra opcin es escribir esto en el archivo settings.xml del directorio raz de nuestro M2, como cuenta este artculo.Flujo general de descarga de componentesA continuacin mostraremos el algoritmo que utiliza Maven para encontrar las dependencias de nuestro proyecto: si no lo tenemos en nuestro repositorio local, lo ir a buscar al repositorio Maven Central, y en ltima instancia, en los repositorios adicionales definidos por nuestro proyecto o la configuracin general de Maven (el archivo settings.xml).Ejecutando maven desde la consolaUna alternativa es trabajar directamente con Maven desde la consola, algo que puede ser til para automatizar tareas, como cuando trabajemos con herramientas de integracin continua.mvn clean compileEsto ejecuta varios plugins en forma sincronizada: por un lado borra los directorios de destino, como hemos contado en el prrafo plugins y luego compila los fuentes del proyecto, lo cual implica descargarse las dependencias, y en el caso del plugin de Xtend, convertir los archivos .xtend a .java (y luego generar los .class)Si queremos ver el rbol de dependencias transitivas, podemos escribirmvn dependency:treePero cmo sabemos qu comando debemos ejecutar? Para eso hay que entender el ciclo de vida de un build de Maven.Ciclos de buildMaven est pensado para todo el ciclo de vida del proyecto. Lo vamos a usar para compilar, para generar cdigo (de ser necesario), para correr los tests, para empaquetar, y hasta para publicar nuestros artefactos generando releases con trazabilidad.Maven define un conjunto de etapas en la construccin (build) de nuestro proyecto. Resumimos algunas ac: generate-sources: generar cdigo, previo a compilacin. compile: compila el cdigo fuente. test: ejecuta los test cases package: genera un paquete con el cdigo (.jar por ejemplo) install: hace pblico el paquete en nuestro repositorio local (ver repositorios locales en las siguiente seccin) deploy: publica el artefacto en un repositorio remoto (ver repositorios locales en las siguiente seccin)Podemos indicar a Maven que ejecute hasta cierta fase. Por ejemplo:mvn compileVa a ejecutar las dos primeras fases.mvn testLas tres primeras. Es decir es igual a mvn compile + correr los tests.De la misma manera podemos trabajar en Eclipse con el plugin M2:Relacin entre plugins y ciclos del buildA continuacin dejamos un diagrama bsico que muestra la relacin entre plugin y el ciclo de vida del build:El grfico no incluye plugins que estamos usando en Algoritmos 2: Xtend, cobertura de tests, etc. pero sirve como referencia para entender qu goals se ejecutarn en base al comando Maven pedido.Resumen general de la arquitectura MavenDocumentacin oficialPara ms informacin recomendamos leer la documentacin oficial del proyecto Maven: POM reference Introduction to the POMY estos links: Maven in 5 minutes Simple Explanation of Maven - video de la Universidad de CincinnatiLinks relacionados Pgina principal de Algoritmos 2" + +} , + +{ + +"title" : "Mejorar la experiencia del pharoer", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/mejorar-la-experiencia-del-pharoer.html", +"date" : "", +"content" : "" + +} , + +{ + +"title" : "Mensajes de colecciones", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/mensajes-de-colecciones.html", +"date" : "", +"content" : "Este es un pequeo resumen de mensajes que entiende una coleccin. Lo que sigue sirve para todos los sabores de colecciones.Qu puedo hacer con los conjuntos de objetos? Muchas cosas, las colecciones entienden mensajes muy tiles para ayudarnos a abstraernos un poquito. Vamos a separarlos en los que tienen efecto colateral sobre la coleccin receptora y los que no.Con efectoEstos mensajes alteran a la coleccin que recibe el mensaje. Si no quiero perder la coleccin original puedo o bien copiar la coleccin mandndole shallowCopy y luego usar estos mensajes, o replantearme si no quera usar alguno de los mensajes de colecciones sin efecto :)Agregarle objetosSmalltalkpajarosadd:pepita.Wollokpajaros.add(pepita)Tambin existe el mensaje addAll: en Smalltalk y addAll(conjunto) en Wollok que recibe otra coleccin y agrega todos los elementos del parmetro a la coleccin receptora.SmalltalkpajarosaddAll:picafloresWollokpajaros.addAll(picaflores)Quitarle objetosSmalltalkpajarosremove:pepita.Wollokpajaros.remove(pepita)Anlogamente al addAll:/addAll(conjunto), existe el removeAll:/removeAll(conjunto) que le quita a la receptora todos los que estn en la coleccin parametrizada.Sin efectoEstos mensajes se pueden mandar tantas veces como queramos sin miedo de alterar la coleccin receptora.Saber cuntos objetos tieneSmalltalkpajarossize.Wollokpajaros.size()Que me devuelve? Un objeto nmero con la cantidad de objetos que conoce.Preguntarle si tiene un objetoSmalltalkpajarosincludes:pepita.Wollokpajaros.contains(pepita)Que me devuelve? Un objeto booleano, true o falseUnirlo o intersectarlo con otro conjuntoSmalltalkgolondrinasunion:picaflores.Wollokgolondrinas.union(picaflores)Que me devuelve? Una nueva coleccin con la unin de ambas.Smalltalkavesintersection:voladores.Wollokaves.intersection(voladores)Que me devuelve? Una nueva coleccin con la interseccin de ambas.Siendo que la unin y la interseccin est pensada para conjuntos matemticos, estos mensajes slo lo entienden los sets.Adems en Wollok puede hacerse:golondrinas+picafloresQue retorna la concatenacin de ambos conjuntos, retornando una coleccin del mismo sabor que la receptora.Seleccionar los elementos que cumplen con un criterioSmalltalkpajarosselect:[:unPajaro|unPajaroestaDebil].usuariosselect:[:unUsuario|unUsuariodeuda&gt;1000].Wollokpajaros.filter({unPajaro=&gt;unPajaro.estaDebil()})usuarios.filter({unUsuario=&gt;unUsuario.deuda()&gt;1000})Que me devuelve? Una nueva coleccin con los objetos que cuando se los evala con el bloque, dan true.Buscar algn elementos que cumpla con un criterioSmalltalkpajarosdetect:[:unPajaro|unPajaroestaDebil].Wollokpajaros.find({unPajaro=&gt;unPajaro.estaDebil()})Que me devuelve? Un objeto de la coleccin que cuando se lo evale con el bloque, de true.Qu pasa si no hay ningn objeto que cumpla la condicin? Explota, lo cual tiene sentido porque no sabe qu hacer si no lo tiene. Por eso existe otra versin en la cual podemos decirle qu devolvernos si no hay ninguno.Smalltalkpajarosdetect:[:unPajaro|unPajaroestaDebil]ifNone:[pajarosanyOne].Wollokpajaros.findOrElse({unPajaro=&gt;unPajaro.estaDebil()},{pajaros.anyOne()})Recolectar el resultado de hacer algo con cada elementoSmalltalkpajaroscollect:[:unPajaro|unPajaroultimoLugarDondeFue].Wollokpajaros.map({unPajaro=&gt;unPajaro.ultimoLugarDondeFue()})Que me devuelve? Una nueva coleccin con los objetos que devuelve el bloque al aplicarlo con cada elemento.Verificar si todos los elementos de la coleccin cumplen con un criterioSmalltalkpajarosallSatisfy:[:unPajaro|unPajaroestaDebil].Wollokpajaros.all({unPajaro=&gt;unPajaro.estaDebil()})Que me devuelve? un booleano que indique si todos los objetos de la coleccin dan true al evaluarlos con el bloque.Verificar si algn elemento de la coleccin cumple con un criterioSmalltalkpajarosanySatisfy:[:unPajaro|unPajaroestaDebil].Wollokpajaros.any({unPajaro=&gt;unPajaro.estaDebil()})Que me devuelve? un booleano que indique si alguno de los objetos de la coleccin da true al evaluarlo con el bloque.Reducir una coleccin haciendo algo un elemento y el resultado de la reduccin con el elemento anteriorSi queremos evaluar un bloque de dos parmetros con cada elemento de la coleccin, usando como primer parmetro la evaluacin previa, y como segundo parmetro ese elemento (o sea, lo que en funcional vimos como fold)Smalltalkpajarosinject:0into:[:inicial:unPajaro|inicial+unPajaropeso]."sumatoriadepesos"pajarosinject:(pajarosanyOne)into:[:masFuerte:unPajaro|(unPajaroenergia&lt;masFuerteenergia)ifTrue:[unPajaro]ifFalse:[masFuerte]]"maximosegunenergia"Wollokpajaros.fold(0,{inicial,unPajaro=&gt;inicial+unPajaro.peso()})//sumatoriadepesospajaros.fold(pajaros.anyOne(),{masFuerte,unPajaro=&gt;if(unPajaro.energia()&lt;masFuerte.energia())unPajaroelsemasFuerte})//maximosegunenergiaQue me devuelve? La ultima evaluacin del bloque.Para qu me sirve? Para muchas cosas: obtener el que maximice o minimice algo, obtener el resultado de una operacin sobre todos (p.ej. sumatoria), y ms. Por lo general existen operaciones de ms alto nivel para la mayora de las reducciones ms comunes, de ser as obviamente es preferible usar esos mensajes en vez de hacer la reduccin.Por ejemplo, en Wollok podramos haber hecho directamente:pajaros.sum({unPajaro=&gt;unPajaro.peso()})pajaros.max({unPajaro=&gt;unPajaro.energia()})Obtener una coleccin de otro saborEn Smalltalk existen los mensajes asSet, asBag, asOrderedCollection y asSortedCollection: que retornan una coleccin nueva a partir de la receptora que tiene otras caractersticas (ver sabores de colecciones). En particular asSet y asSortedCollection: son de uso ms comn para quitar repetidos u ordenar en base a un criterio respectivamente.usuarios.asSortedCollection:[:usuarioJoven:usuarioViejo|usuarioJovenedad&lt;usuarioViejoedad]En Wollok, al slo haber sets y listas, lo que ambas entienden son asSet() y asList(). Las listas ordenadas por un criterio pueden obtenerse mediante el mensaje sortedBy(criterio), que retorna una nueva coleccin con los elementos de la receptora ordenadas segn el bloque recibido.usuarios.sortedBy({usuarioJoven,usuarioViejo=&gt;usuarioJoven.edad()&lt;usuarioViejo.edad()})A su vez en Wollok tambin existe el mensaje sortBy(criterio) que se diferencia en que en vez de retornar una nueva coleccin ordenada de esa forma, modifica la coleccin receptora para quedar ordenada as. O sea, produce un efecto colateral.Y la iteracin?El mensaje do: en Smalltalk o forEach(bloque) en Wollok, sirve para hacer algo con cada objeto de la coleccin. Este mensaje en s mismo no tiene efecto colateral, pero tampoco tiene un valor de retorno que pueda interesarnos. Entonces, cundo se usa? Slo tiene sentido usar este mensaje cuando lo que queremos hacer sobre cada elemento (o sea, el bloque) s produce un efecto.Smalltalkpajarosdo:[:unPajaro|unPajarovola:100].Wollokpajaros.forEach({unPajaro=&gt;unPajaro.vola(100)})Yo no pretendo recolectar resultados, slo quiero que pasen cosas con cada elemento.Importante: no usar el do:/forEach para todo, los mensajes que vimos anteriormente son abtracciones mucho ms ricas que nos permiten concentrarnos en nuestro objetivo y no en el algoritmo para lograr el resultado, seamos declarativos!" + +} , + +{ + +"title" : "Mensajes y metodos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/mensajes-y-metodos.html", +"date" : "", +"content" : "DefinicionesUn mensaje es algo que yo le puedo decir a un objeto.Un mtodo es una secuencia de lneas de cdigo que tiene un nombre.Cuando se le enva un mensaje a un objeto, se activa un mtodo cuyo nombre coincide con el mensaje enviado. La palabra mtodo puede entenderse como forma, describe la forma en que algunos objetos responden a un determinado mensaje cuando alguien se los enva.P.ej. si tengo un objeto referenciado por la variable pepe, y pongoSmalltalk:pepedireccionWollok:pepe.direccion()entonces estoy enviando el mensaje direccion se va a activar un mtodo llamado direccion. Qu mtodo? El que decida el method lookupA quines se le pueden mandar mensajes en un mtodo? A los objetos que conocidos mediante atributos A los objetos que me pasan por parmetro A m mismo usando self A los objetos bien conocidos (incluyendo a los literales)Importante no olvidar Los mensajes los entienden los objetos Si a un objeto que entiende el mensaje m le envio el mensaje m entonces se va a activar el mtodo m para ese objeto Cuando en un mtodo dice self, es una referencia al objeto que recibi el mensaje por el cual se activ el mtodo.En el ejemplo, si en el mtodo direccion dice self, entonces al hacer pepe direccion este self va a ser una referencia al objeto referenciado por pepe." + +} , + +{ + +"title" : "Metamodelo", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/metamodelo.html", +"date" : "", +"content" : "Un modelo es una descripcin abstracta que describe aquello que se desea construir. Al definir un modelo uno sigue un conjunto de reglas. Por ejemplo: en un diagrama de secuencia las flechas (mensajes) entre las lneas deben darse de determinadas maneras, no pueden tener cualquier organizacin porque no tendra sentido. A este conjunto de reglas lo denominamos metamodelo.El metamodelo nos dice: qu tipo de abstracciones podemos usar en nuestro modelo (por ejemplo: clases) qu caractersticas podemos asociarle a esas abstracciones (por ejemplo: mtodos, atributos) qu mecanismos tenemos para relacionar esas abstracciones entre s (herencia, asociacin)Al construir, si utilizamos un lenguaje de alto nivel (o sea, no assembler) ese lenguaje tambin tendr la capacidad de especificar abstracciones dentro del lenguaje, como procedimientos, funciones, tipos abstractos de datos, clases, objetos, herencia, polimorfismo, aspectos, mixins, servicios, componentes, etc. Obviamente, las abstracciones que puedo construir en un lenguaje dado, dependen tambin de un conjunto de reglas; dicho de otra manera el lenguaje tiene su propio metamodelo." + +} , + +{ + +"title" : "Metaprogramacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/metaprogramacion.html", +"date" : "", +"content" : "ConceptoMetaprogramacin es el proceso o la prctica por la cual escribimos programas que generan, manipulan o utilizan otros programas.Ejemplos: Un compilador se puede pensar como un programa que genera otro programa. Un formateador de cdigo es un programa que manipula otro programa. Una herramienta como javadoc utiliza nuestro programa para generar su documentacin.Para qu se usa la metaprogramacin ?En general la metaprogramacin se utiliza ms fuertemente en el desarrollo de frameworks. Simplemente porque un framework va a resolver cierta problemtica de una aplicacin, pero no va a estar diseado para ninguna en particular. Es decir, la idea de framework es que se va a poder aplicar y utilizar en diferentes dominios desconocidos para el creador del framework.Entonces estos frameworks van a manipular objetos, sin conocerlos de antemano.Ejemplos: ORMs como hibernate: que van a encargarse de persistir las instancias de nuestras clases sin siquiera conocerlas de antemano. Frameworks de UI: que debern saber mostras cualquier objeto. Otras herramientas: javadoc: es una herramienta como el compilador de java, que lee el cdigo fuente y genera documentacin html. code coverage: herramientas que miden cunto de nuestro cdigo es realmente ejecutado al correr los tests, y cuales lineas no. analizadores de cdigo: que evalan nuestro cdigo y genera mtrics o miden violaciones a reglas definidas. Como el estilo de cdigo, complejidad ciclomtica, etc. Por ejemplo para java existe sonar que junto a maven automatizan y concrentran varias otras herramientas. Modelos y metamodelosAs como todo programa construye un modelo para describir su dominio. El domino de un metaprograma es otro programa denominado programa objeto o base y tendr un modelo que describe a ese programa, al que llamamos metamodelo.En el siguiente ejemplo, nuestro dominio contiene diferentes tipos de animales, entre ellos perros y humanos.El programa describe las caractersticas de los elementos del dominio utilizando (por ejemplo) clases, mtodos y atributos. Entonces, el modelo contiene una clase Perro, que modela a los perros en el domino. Y el programa manipula instancias de la clase Perro.Un metaprograma tendr a su vez un (meta)modelo que describe a su dominio, el programa base. As como en el dominio hay animales concretos, los habitantes del metadominio (= programa base) sern los elementos del programa: por ejemplo, clases, atributos, mtodos. Entonces el metamodelo deber tener clases que permitan describir esos conceptos, por ejemplo en el metamodelo de Java encontraremos las clases Class, Method, Field. Este metamodelo describe la estructura posible de un programa Java. En otro lenguaje, ese metamodelo tendra diferentes elementos.As como el programa manipula las instancias de las clases Perro o Animal, el metaprograma manipula las instancias de las clases que conforman el metamodelo (Class, Method, Field, o las que fueran).Los lenguajes pueden proveen herramientas de Reflection para trabajar sobre su propio metamodelo.Ejemplo de metaprogramacin en Java: XUnitEjemplo de metaprogramacin en Ruby: XUnit" + +} , + +{ + +"title" : "Method lookup", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/method-lookup.html", +"date" : "", +"content" : "Es el mecanismo por el cual se determina para el envo de un mensaje qu mtodo se debe ejecutar. Este mecanismo puede variar en funcin de la tecnologa usada, la explicacin que se da a continuacin se basa en Smalltalk usando clases, para leer sobre este mecanismo usando prototipos ver Prototipado.Qu pasa cuando a un objeto i instancia de la clase C se le enva un mensaje de nombre m?Tenemos (a efectos de entender el mecanismo porque esto lo hace internamente el ambiente) que mantener una referencia a la clase donde estamos buscando en un momento determinado.Al principio la clase actual es C por ser la clase a partir de la cual instanciamos al objeto receptor del mensaje que es i.El algoritmo es el siguiente:1. se busca en la clase actual un mtodo con el nombre m1a. si se encuentra se ejecuta el mtodo encontrado; se ejecuta el mtodo en el objeto i y se termin el method lookup1b. si no se encuentra y la clase actual no es Object la clase actual pasa a ser la superclase de la clase actual y se vuelve a 1.1c. si no se encuentra y la clase actual es Object entonces el objeto i no entiende el mensaje mEl comportamiento por defecto en Smalltalk cuando un objeto no entiende un mensaje es lanzar un error. Esto se logra a travs del envo de un mensaje llamado #doesNotUnderstand: al objeto i (el mtodo #doesNotUnderstand: est definido en la clase Object)Ejemplo bsicoSi le enviamos el mensaje asUppercase al objeto 'hola' (o sea, al string 'hola') qu debera pasar?Asumamos (porque no es as) que 'hola' es instancia de String, que String es subclase de Collection y que Collection es subclase de Object.Siguiendo el algortmo de arriba a travs de los pasos indicados con -i es 'hola'clase actual es Stringm es #asUppercase- se busca en String un mtodo con el nombre #asUppercase- se encuentra el mtodo #asUppercase en la clase String- se ejecuta el mtodo #asUppercase de la clase String sobre i el objeto receptor del mensaje (o sea hola)Conclusin: 'hola' entiende el mensaje #asUppercaseEjemplo (heredando un mtodo)Basndonos en el ejemplo 1, si le enviamos el mensaje isNil al objeto 'hola' (o sea, al string 'hola') qu debera pasar?i es 'hola'clase actual es Stringm es #isNil- se busca en String un mtodo con el nombre #isNil- no se encuentra el mtodo #isNil en String y la clase actual no es Object entonces la clase actual pasa a ser Collection (la superclase de la clase actual) y se vuelve a 1.- se busca en Collection un mtodo con el nombre #isNil- no se encuentra el mtodo #isNil en Collection y la clase actual no es Object entonces la clase actual pasa a ser Object (la superclase de la clase actual) y se vuelve a 1.- se busca en Object un mtodo con el nombre #isNil- se encuentra el mtodo #isNil en la clase Object- se ejecuta el mtodo #isNil de la clase Object sobre i el objeto receptor del mensaje (o sea hola)Conclusin: 'hola' entiende el mensaje #isNilEs importante entender que, independientemente de dnde se mande un determinado mensaje (por ejemplo, podra ser en un mtodo heredado donde se mande un mensaje a self), el method lookup va a arrancar por la clase a partir de la cual se instanci el objeto. Lo nico que puede alterar este mecanismo para empezar a buscar desde una clase distinta es si se mand el mensaje a super.Ejemplo (no entiende el mensaje)Basndonos en el ejemplo 1, si le enviamos el mensaje factorial al objeto 'hola' (o sea, al string 'hola') qu debera pasar?i es 'hola'clase actual es Stringm es #factorial- se busca en String un mtodo con el nombre #factorial- no se encuentra el mtodo #factorial en String y la clase actual no es Object entonces la clase actual pasa a ser Collection (la superclase de la clase actual) y se vuelve a 1.- se busca en Collection un mtodo con el nombre #factorial- no se encuentra el mtodo #factorial en Collection y la clase actual no es Object entonces la clase actual pasa a ser Object (la superclase de la clase actual) y se vuelve a 1.- se busca en Object un mtodo con el nombre #factorial- no se encuentra y la clase actual es Object entonces el objeto i no entiende el mensaje mO dicho de otra forma, 'hola' no entiende el mensaje #factorial" + +} , + +{ + +"title" : "Method missing", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/method-missing.html", +"date" : "", +"content" : "Method missing (o Does not understand en Smalltalk) es un punto de intercepcin en el method lookup que ofrecen algunos lenguajes para definir cdigo a ejecutar si el objeto receptor no entiende el mensaje recibido. Si el method lookup falla, el objeto receptor recibir el mensaje method_missing que en Object lanza un error por no entender el mensaje, pero qu pasa si redefinimos este mensaje?Poder interceptar el method lookup de esta forma y redefinir lo que debera suceder en caso de que un objeto de la clase A no entienda el mensaje recibido es una herramienta muy poderosa ya que permite armar definiciones genricas para cualquier mensaje (o para un amplio conjunto que nosotros estemos interesados).Algunos ejemplos de uso: en ocasiones es til usar un objeto que ante cualquier mensaje no haga nada, pero tampoco explote (un deaf object), en este caso la implementacin es trivial ya que un method_missing vaco har que la interfaz de nuestro objeto sea infinita. se puede usar para hacer APIs que, en base a algn patrn del nombre del mensaje, se pueda ejecutar una lgica particular. Por ejemplo, en Ruby on Rails se pueden consultar todos los objetos persistidos que cumplan un cierto criterio en base a los atributos de los mismos con un mensaje a la clase find_by que recibe un diccionario:Person.find_by(user_name:user_name,password:password)Pero tambin se puede usar de la siguiente forma:Person.find_by_user_name_and_password(user_name,password) si se quiere implementar un decorator para lo cual el decorador tendr muchos mtodos que sean slo delegar en el decorado el mismo mensaje que recibi, podra resolverse el dispatch de forma genrica en el method_missing y slo definir aquellos mtodos en los cuales s existe alguna lgica propia que aportar.Supongamos que queremos hacer el method_missing para nuestro decorador, podra ser algo como:defmethod_missing(symbol,*args,&amp;block)if@decorado.responds_to?(symbol)@decorado.send(symbol,*args)elsesuperendendDe esa forma si el objeto decorado entiende el mensaje, se lo mandar, de lo contrario ejecutar method_missing de la superclase." + +} , + +{ + +"title" : "Metodos de clase para crear objetos inicializados", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/metodos-de-clase-para-crear-objetos-inicializados.html", +"date" : "", +"content" : "A veces, es necesario inicializar alguna/s de la/s variable/s de un objeto, con objetos fijos, o con objetos que hay que pasarle apenas se crea el objeto.Para esto hacemos un mtodo al que por convencin se lo llama initialize, y le enviamos el mensaje correspondiente a cada objeto que creamos desde el workspace. Por ejemplo#Camioninitializeviajes:=Setnew.desgasteDeLasRuedas:=0.puedeViajar:=true.chofer:=unFerchochofer:=unFercho"...enelworkspace..."elReyDelAcceso:=Camionnew.elReyDelAccesoinitialize.elReyDelAccesoconductor:cacho."cacholotenacreadomsarribaenelworkspace"Ahora bien, seran muy felices dos cosas ahorrarme el decirle inicialize a cada Camion que creo poder pasarle el chofer al camin en el momento de crearlo,Con la lazy inicialization, puedo lograr lo primero pero no lo segundo.Una forma de lograr las dos cosas es definir un mtodo de clase que tiene como objetivo crear un objeto ya configurado y listo para usar.Cmo hacemos? Fcil#CamionclassnuevoConducidoPor:unFercho|camionNuevo|camionNuevo:=selfnew.camionNuevoinitialize.camionNuevochofer:unFercho.^camionNuevoVemos que el mtodo crea un camin nuevo envindose un mensaje a self, que es la clase Camion. lo configura lo devuelve (muuuuy importante)En el workspace nos quedaelReyDelAcceso:=CamionnuevoConducidoPor:cacho.qu ganamos? que no nos olvidamos de inicializar ningn camin que el workspace queda ms compacto, importante para los workspace de TP que pueden implicar la creacin de muchos objetos. que si le digo a la gente que va a usar los camiones que los cree siempre dicindole a la clase lo que yo les indico, todos los camiones van a nacer ya con chofer asignado, lo que tal vez es necesario para que los camiones no den errores despus." + +} , + +{ + +"title" : "Min y max", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/min--y-max-.html", +"date" : "", +"content" : "ejemplo: un remis cobra 2 pesos por kilmetro, mnimo 5 pesos. Tengo que escribir el mtodo precioViaje: en la clase Remis. Hago esto?precioViaje:unViaje|precio|precio:=2*unViajedistancia.precio&gt;=5ifTrue:[^precio]ifFalse:[^5]nuuuuuuu los programadores objetosos con estilo slo usan min: y max:. Estos mensajes los entienden los nmeros, reciben otro nmero como parmetro, y devuelven el ms chico / ms grande entre self y el parmetro. Pueden probar esto en un workspace3min:83max:83min:13max:1Entonces cmo queda el precioViaje:? Lo que tengo que devolver es el mximo entre 5 y el resultado de la cuenta (pinsenlo ), entonces queda asprecioViaje:unViaje^5max:(2*unViajedistancia)bel-lezaPara practicar, hagamos que a un remis le pueda preguntar la cantidad de pasajeros legal, que es la que tiene, pero nunca puede ser ms de 5. O sea, si en realidad lleva 7 personas, la cantidad legal es 5. el consumo por combustible, que es 1 litro cada 8 km, mnimo 2 litros.Los remises entienden distancia y cantPasajeros" + +} , + +{ + +"title" : "Mixins", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/mixins.html", +"date" : "", +"content" : "Similares a los Traits, estas construcciones, que proveen la implementacin de un conjunto de mtodos, pueden ser combinadas y conforman un mecanismo de comparticin de cdigo complementario a las clases. Su principal diferencia con los Traits es que pueden definir y acceder a variables y su combinacin no producen conflictos, ya que estos se resuelven automticamente por un mecanismo de linearization.Los Mixins tienen implementaciones en varios de los lenguajes ms modernos, como ser Ruby, Scala (en el lenguaje se les dice trait, pero son mixins), Python y Groovy.Gracias al mecanismo de linearization, los mixins resuelven el problema del rombo o diamante presente en la herencia mltiple, definiendo una precedencia entre los mixins que componen una clase dependiendo del orden de composicin, es decir, si la clase C se compone de los mixins {A, B}, se tomarn los mtodos de B en los casos en los que se presenten conflictos. Como consecuencia de esta decisin de diseo de los mixins, resultar diferente la composicin {A, B} que {B, A}.DescripcinUn Mix-In es una subclase abstractas: como una subclase que no est ligada a ninguna superclase. Se puede aplicar a cualquier superclase (can be mixed-in)Se puede ver como una refactorizacin de la herencia hacia una chain of resposibilities. En una herencia normal, cada clase (nodo) de la cadena, conoce exactamente a su siguiente (superclase). Por lo que la cadena es rgida. Un mixin es un nodo que no conoce est atado al siguiente en la cadena, aunque puede usarlo (como en el chain of resposibilities de GoF). Por lo que se puede reutilizar y aplicar a diferentes cadenas.Concepto Cumplen el rol de la reutilizacin que cumple una clase, sin tener el rol de ser generadores de instancias. Representan o modelan un cierto feature que puede ser reutilizado y aplicado a varias clases en diferentes jerarquas Generalmente se utilizan para roles o caractersticas de una clase como Observable. No presentan el problema del diamante de la herencia mltiple, ya que el orden de composicin acta como tcnica de resolucin implcita. Es decir el primer mixin declarado que entienda el mensaje lo va a responder.Clasificacin Completo: cuando todo su comportamiento depende de s mismo y no de un comportamiento externo (definido en la clase sobre la que se aplica). Parcial: cuando su comportamiento usa/delega/depende de otro comportamiento de la clase sobre la que se aplica.Ejemplos Uso de mixins en Ruby Uso de mixins en Scala Juegos de EstrategiaEn Scala es posible, no slo aplicar el mixin estticamente en la jerarqua, sino tambin al instanciar un objeto particular. En este ejemplo vemos una alternativa al decorator basado en mixins: Stackable Trait PatternPapersMixin-Based Inheritance" + +} , + +{ + +"title" : "Modelando objetos responsabilidades y delegacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/modelando-objetos---responsabilidades-y-delegacion.html", +"date" : "", +"content" : "A la hora de querer resolver un problema parados en el paradigma de objetos, hay ciertas cuestiones bsicas que debemos tener en cuenta para triunfar y ser felices :). De todas aquellas, vamos a nombrar principalmente a las que se destacan en este paradigma en contraposicin de los otros que conocemos (lgico, funcional y estructurado o procedural).ObjetoCuando programamos en objetos, debemos pensar en objetos. Solo tenemos objetos a los que mandarles mensajes para que nos resuelvan nuestro problema. A su vez, a veces es conveniente tener muchos objetos, para poder partir el problema en varias partes ms pequeas y que sea sencillo resolver cada parte por separado. Cada un de esos otros objetos van a tener una responsabilidad.ResponsabilidadEs aquello que hace un objeto. Aquello que nosotros queremos que haga. Si tenemos un solo objeto que hace demasiadas o todas las tareas de nuestro programa (a.k.a. God Object), probablemente sea complicado que nuestro programa cambie y resuelva nuevos problemas. Va a ser complicado saber si funciona correctamente (testearlo). Va a ser complicado arreglar los errores que tenga!! (si es que los tiene). Si tenemos varios objetos con menos responsabilidades cada uno (mas chiquitos), va a ser ms sencillo intercambiarlos usando polimorfismo, reutilizar partes de cdigo en otras partes de nuestro programa, evitar repeticiones de lgica Por esas razones, es que queremos que nuestros objetos tengan bien repartidas las responsabilidades entre ellos.Delegacion y ColaboracinCuando tenemos bien repartidas las responsabilidades entre nuestros objetos, probablemente hayamos encontrado varios objetos. Ahora, cada uno resuelve su problema Cmo los pegamos? Los objetos se conocen a travs de referencias, y as pueden mandarse mensajes. Cuando un objeto resuelve parte de un problema y le pasa otra parte del problema a algun objeto que conozca, hablamos que ambos objetos estan colaborando. As, cuando un objeto le encarga toooda la tarea a resolver a otro objeto, decimos que este delega la responsabilidad.EjemploSupongamos que queremos que un tanque que dispara misiles trmicos le dispare a otro tanque. El dao que hace un misil trmico es 10 veces la cantidad de ocupantes del tanque al que es disparado. El tanque enemigo tiene una coraza que va decrementando a medida que recibe dao (el mismo es destrudo cuando la coraza llega a 0) y debe ser manejado por 3 personas. Una solucin bien delegada podra ser:objecttanqueDeMisiles{varmisil=misilTermicomethoddispararA(otroTanque) {otroTanque.recibirDanio(misil.cuantoDanioPara(otroTanque))}}objecttanqueEnemigo{varcoraza=100methodrecibirDanio(cant){coraza=(coraza-cant).max(0)}methodcantidadOcupantes() {return3}}objectmisilTermico{methodcuantoDanioPara(unTanque){returnunTanque.cantidadOcupantes()*10}}Es particularmente importante que la forma de recibir dao est delegada en el tanque enemigo, ya que no hay ningn motivo para que el tanque de misiles sepa de la existencia de una coraza del enemigo (mejor en trminos de encapsulamiento).El mismo ejemplo en Smalltalk:#TanqueDeMisiles&gt;&gt;dispararA:otroTanqueotroTanquerecibirDao:(misilcuantoDaoPara:enemigo).#TanqueEnemigo&gt;&gt;recibirDao:cantcoraza:=(coraza-cant)max:0&gt;&gt;cantidadOcupantes^3#MisilTermico&gt;&gt;cuantoDanioPara:unTanque^unTanquecantidadOcupantes*10" + +} , + +{ + +"title" : "Monada", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/monada.html", +"date" : "", +"content" : "Este artculo est en construccin. Functors, Applicatives, And Monads In Pictures Un artculo con la introduccin a las mnadas: http://james-iry.blogspot.com/2007/09/monads-are-elephants-part-1.html Formulacin alternativa de mnadas: http://en.wikipedia.org/wiki/Monad_(functional_programming)#fmap_and_join" + +} , + +{ + +"title" : "No hay instancias para el Show", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/no-hay-instancias-para-el-show.html", +"date" : "", +"content" : "A muchos probablemente les haya sucedido encontrarse con el error No instance for Show. Esto, contrario a lo que muchos creen, no significa que nos quedamos sin show por falta de instancias.Lo que significa es, en criollo, ARRRGH, no s mostrar esto en la consolaSlo que lo dice aproximadamente as:&lt;interactive&gt;:2:1: No instance for (Show (a0 -&gt; Bool)) (maybe you haven't applied enough arguments to a function?) arising from a use of print In the first argument of print, namely it In a stmt of an interactive GHCi command: print itSolucin rpidaLa mayora de los datos son mostrables. Si yo quiero mostrar un 3, la consola lo sabe mostrar:Main&gt; 33Pero no puedo mostrar una funcin:Main&gt; even&lt;interactive&gt;:2:1: No instance for (Show (a0 -&gt; Bool)) (...)Solucin rpida 1Arriba de todo en el archivo .hs escribir:import Text.Show.FunctionsEsto hace que las funciones sean mostrables:Main&gt; even&lt;function&gt;Solucin rpida 2En realidad, tcnicamente lo que estamos haciendo al hacer el import de Text.Show.Functions es lo mismo que agregar esto al principio de nuestro archivo:instance Show (a -&gt; b) where show f = "&lt;una funcin&gt;"Esto hace que las funciones sean mostrables:Main&gt; even&lt;una funcin&gt;ExplicacinPara entender ms sobre el tema, se recomienda la lectura de Definiendo nuestros TiposTambin se recomienda la lectura de Learn you a Haskell, el captulo sobre clases de tipos" + +} , + +{ + +"title" : "Nombres de clases", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/nombres-de-clases.html", +"date" : "", +"content" : "Singular o plural?Partimos de que una clase representa un concepto, y cada instancia de esa clase va a representar a un ente que corresponde a ese concepto.P.ej. la clase Golondrina representa al concepto de ser golondrina, cada instancia representa a una golondrina (un ente de la vida real que en el contexto del software que estoy construyendo corresponde al concepto Golondrina).El nombre de una clase debe referirse a lo que va a representar una instancia cualquiera. Si le pongo Golondrina a una clase, es porque cada instancia va a representar a una golondrina.Entonces, si p.ej. a una clase le pongo Camiones, qu quiere decir?. Que cada instancia va a representar a un conjunto de camiones. Si quiero que cada instancia represente a un camin, entonces est mal ponerle plural al nombre de la clase, en este caso debera llamarse Camion." + +} , + +{ + +"title" : "Normalizacion en objetos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/normalizacion-en-objetos.html", +"date" : "", +"content" : "ObjetivoEl proceso de normalizacin se origina con el esquema relacional y ha sido ampliamente estudiado y difundido, ya que los RDBMS surgieron como una alternativa a los motores de bases de datos jerrquicos que permitan redundancia de la informacin y tenan problemas de consistencia, lo que llevaba a tener datos faltantes o duplicados.Si bien el modelo de objetos tiene algunas caractersticas diferenciales respecto al relacional, podemos encontrar decisiones que tienen que ver con la aplicacin (o no) de la normalizacin y el almacenamiento redundante de la informacin.EjemploConsideraremos como ejemplo un dominio conocido: la relacin many-to-many entre alumnos y cursos. Un alumno se inscribe en varios cursos y en cada curso tenemos muchos alumnos.Recordemos qu busca la normalizacin Evitar redundancias Evitar inconsistencias: no quiero que un profesor renuncie y el curso quede apuntando a un profesor inexistente Reducir el impacto de los cambios en los datos: si cargu mal la informacin de un profesor, debera actualizarlo en un solo lugarPrimer modelo posibleEl alumno tiene como atributos nombre, y los cursos. El curso tiene el nombre del profesor (un String) y los alumnos que participan.Aplicando reglas de normalizacin (o no)Campos calculadosEs una tcnica usual en muchas tecnologas, en objetos tambin. Podramos pensar ejemplos: la cantidad de alumnos de un curso la cantidad de alumnos de un curso en condiciones de firmar el promedio de notas de un alumno en un cursose trata de atributos que pueden calcularse pero que por algn motivo elegimos almacenarlos como dato, ya sea1) porque es conveniente cuando lo migramos a un esquema relacional, para facilitar las consultas posteriores, ej: conocer los cursos con ms de 40 alumnos seraselect*fromcursoscwherec.cantidad_alumnos&gt;40Mientras que si no estuviera ese dato necesitaramos hacer un join con la tabla de relacin cursos-alumnos + el correspondiente count.2) porque queremos mejorar la performance, aun en objetos, en especial cuando es ms frecuente consultar la cantidad de alumnos en un curso vs. inscribir un alumno a un cursoCampos calculados vs. datos del negocio no siempre calculablesSi necesitamos saber cuntos inscriptos hubo al comienzo del cuatrimestre, debemos tener en cuenta que el campo se puede calcular en un momento t0 pero una vez pasado ese momento, el clculo puede perderse (por ejemplo porque algn alumno abandona la cursada o se cambia de curso)Este requerimiento no tiene nada que ver con la normalizacin, porque no hay redundancia, en ese caso lo que tenemos que hacer es crear un atributo en el Curso1FN: Aplicabilidad en objetosLa primera forma normal nos pide que no haya filas duplicadas, y esto se da mediante la identificacin de claves candidatas no haya campos repetitivos / atributos multivaluadosAqu vemos que las restricciones de primera forma normal no aplican para el modelo de objetos, dado que no existe el concepto de relacin o tabla como punto de concentracin de todos los alumnos. Cada alumno que se crea forma parte del ambiente mientras tenga una referencia, y no hay riesgo de filas duplicadas ni necesidad de usar una clave candidata, ya que cada objeto nuevo tiene su propia identidad respecto a los dems objetos.Por otra parte, un alumno puede tener una coleccin de cursos y cada curso una coleccin de alumnos (o un mapa alumno-notas). La restriccin de no tener atributos multivaluados, o un atributo subdivisible en una estructura interna no aplica tampoco al modelo de objetos, donde la referencia es a cualquier tipo de objeto, incluido una coleccin.2FN y 3FN en objetosTanto 2 como 3FN buscan que todo determinante sea clave candidata, o explicado en una manera ms simple, no haya dependencias de ningn atributo con otro atributo que forme parte de la clave principal que no forme parte de la clave principalDado que en objetos no utilizamos el concepto de clave primaria, no tiene sentido discriminar cada caso en particular. Lo que s podemos revisar es el ejemplo nuevamente, donde en el objeto Curso se registra la informacin sobre el legajoDocente (un entero) y el nombreDocente (un String).pasa aNosotros podemos llegar a encontrar una abstraccin Docente de dos maneras posibles: aplicando la lgica de normalizacin, donde vemos que existe una dependencia funcional entre el nombre del docente y su legajo (slo que el legajo y el nombre forman parte de la abstraccin Docente y la forma de normalizarlo implica generar una referencia del curso hacia el objeto Docente) o bien mucho antes, cuando necesitamos la abstraccin Docente, porque es necesario agregarle comportamientoEl proceso de normalizacin de entidades en el esquema relacional surge naturalmente como un proceso de generacin de abstracciones posibles en el modelo de objetos.Por ltimo, podramos decidir que nuestro objeto Curso tuviera los atributos docente (una referencia a un objeto Docente), legajoDocente y nombreDocente por dos motivos: uno de negocio, si como en el caso anterior necesitramos almacenar la informacin del docente en el momento de tomar el curso para mejorar la performance, en ese caso introducimos una redundancia desnormalizando la informacin del curso. Eso permite que podamos obtener la informacin de un curso sin necesidad de navegar hacia otras entidades (dejando la referencia al docente en modo LAZY), algo que todo diseador debe contemplar para los casos de uso que el negocio exige.Redundancias por problemas de navegabilidadEl modelo relacional es sumamente flexible, en una relacin many-to-many Alumno-Curso, podemos navegar la relacin partiendo desde el curso o bien desde el alumno. En cambio, si en el modelo de objetos necesitamos resolver estos requerimientos saber qu alumnos del curso de Diseo aprobaron el primer parcial saber en cuntos cursos est anotado un alumno de lunes a viernesEs mucho ms fcil encarar estos objetivos si la relacin de asociacin entre Alumno y Curso es bidireccional, es decir que un alumno conoce la lista de cursos en los que est inscripto y un curso conoce la lista de alumnos que forman parte.ResumenEn el modelo de objetos podemos aplicar ciertas reglas de normalizacin o redundancia, generando referencias hacia nuevas entidades o bien duplicando la informacin de un objeto en otro.Diferencias entre el modelo relacional y el de objetos Modelo relacional Objetos Elimina duplicados mediante la primary key Trabaja con identidad, no necesita claves naturales ni subrogadas No permite atributos multivaluados Permite referenciar a cualquier tipo de objeto, incluido conjuntos y mapas Es un modelo flexible para navegar en cualquier direccin Las referencias tienen una sola direccin, para tener una relacin bidireccional es necesario utilizar otra referencia Puedo manipular los datos, los triggers o constraints me permiten asegurar la consistencia de los datos No accedo directamente a los datos sino que envo mensajes, y los mtodos permiten asegurar la consistencia del estado de cada objeto " + +} , + +{ + +"title" : "Notacion point free", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/notacion-point-free.html", +"date" : "", +"content" : "A veces, como consecuencia de definir solamente en trminos de Aplicacin Parcial y/o Composicin de funciones, escribir explcitamente los parmetros de la misma se vuelve redundante.Por ejemplo, se podra escribiresMultiploDeab=((==0).(`mod`a))bSin embargo, lo que est dentro del parntesis principal ya es una funcin que hace lo que queremos, con el tipo adecuado. Por lo que puede reescribirse de la siguiente manera:esMultiploDea=(==0).(`mod`a)Lo cual se conoce como notacin point-free, la cual es interesante porque pone nos permite concentrarnos en la combinacin de las funciones en lugar del pasaje de paramtro, subiendo as nuestro nivel de abstraccin.Al principio puede generar cierta confusin sobre la pregunta cuantos parmetros recibe la funcin?. As que analicemos algunos casos concretos.Una reglita bsicaLa regla es que una funcin como esa tiene tantos parmetros como la suma entre: Los parmetros que aparecen a la izquierda del igual. Los parmetros que le faltan a la expresin a la derecha del igual.Analizando el caso anterior vemos: Un parmetro a la izquierda del igual: a. (Esta parte es la ms directa.) La expresin de la derecha es una composicin y por lo tanto una funcin a-&gt;b entonces le falta un parmetro. En total la funcin recibe dos parmetros.Analizando un poco ms los tiposPara no confundirse, en la forma ms tradicional de escribir funciones a la expresin a la derecha del igual no le falta ningn parmetro:siguientex=x+1Se ve claramente que x+1 es una expresin que denota un valor numrico y no una funcin, o dicho de otra manera no le faltan parmetros. En cambio s le faltaran si uno pusiera por ejemplo (+1).La definicin anterior es totalmente equivalente a:siguiente=(+1)Al aplicar parcialmente la funcin (+) :: Num a =&gt; a -&gt; a -&gt; a obtenemos otra funcin que es del tipo Num a =&gt; a -&gt; a. Si siguiente es igual a la funcin (+1), entonces su tipo es el mismo que el de (+1).En general lo ms comn es ver funciones que slo les falta el ltimo parmetro, como en el caso de esMultiploDe, ya que est definida en funcin de una composicin. No sera correcto definirla de esta forma a pesar de que ambos parmetros vayan en ese orden aplicados al final:esMultiploDe=(==0).flipmodComo no coincide la imagen de la funcin flip modflipmod::Integralc=&gt;c-&gt;c -&gt; ccon el dominio de (==0)(==0)::(Eqa,Numa)=&gt;a-&gt;BoolLa composicin de estas dos funciones no es correcta (de hecho esa expresin tipa, pero no lo van a poder usar porque el tipo de esMultiploDe requerira un nico argumento que sea a la vez una funcin y un nmero equiparable y como que no tiene mucho sentido)Este otro ejemplo s sera correcto:resto=flipmodEl tipo de la funcin resto es el mismo que el de la funcin flip mod que ya mostramos antes.Pros y Cons de la notacin point-freeA favor de usar la notacin point-free es que nos fuerza a dejar de pensar en funcin de la aplicacin y los valores con los que estamos acostumbrados a trabajar, teniendo que pensar en definir funciones como equivalencia de otras funciones combinadas. El paradigma funcional se basa en la idea de combinar funciones, ellas son las divas de esta forma de pensar la programacin, por eso cuando definimos funciones como composicin de otras funciones y/o a la aplicacin parcial de las mismas con estilo point-free, el cdigo resultante es ms limpio :)La notacin point-free puede llevar a ofuscar el cdigo cuando se usa malintencionadamente. Al combinar funciones puede que se vuelva ms complicado inferir mentalmente el tipo de una expresin ya que cuesta ms deducir la cantidad de parmetros necesarios para que la funcin definida se reduzca a un valor concreto mediante la aplicacin.Otro problema que podra surgir dada una funcin compleja escrita de esta forma es que al intentar introducir un cambio menor de funcionalidad en la misma haya que hacer un cambio radical en el cdigo, sin embargo para el nivel de paradigmas esto no debera suceder." + +} , + +{ + +"title" : "Manejo de dependencias con NPM", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/npm-dependencias.html", +"date" : "", +"content" : "Versionado semnticoRecordemos que todo componente tiene una versin compuesta por tres nmeros: major minor patchEjemplo: el componente typescript tiene la versin 3.6.3, donde 3 es el major number, 6 el minor y finalmente 3 es el patch.Para respetar el versionado semntico, al liberar una nueva versin tenemos que indicar qu es lo que trae ese nuevo componente: si soluciona bugs, debera incrementar el patch: el componente typescript pasara a tener la versin 3.6.4 si trae nuevos features o funcionalidades que no rompen la retrocompatibilidad, debera incrementar el minor a 3.7.0 si trae nuevas funcionalidades que rompen la retrocompatibilidad (ej. mtodos o clases que dejaron de existir, o tienen diferente cantidad de parmetros), deberamos incrementar la major a 4.0.0Dependencias de un proyecto con NPMpackage.jsonEl Node Package Manager (NPM) almacena las dependencias de nuestro proyecto (entre otras configuraciones) en el archivo package.json, por ejemplo: "dependencies": { "@angular/animations": "^8.2.7", "@angular/common": "^8.2.7", "@angular/compiler": "^8.2.7", "@angular/core": "^8.2.7", }, "devDependencies": { "@angular-devkit/build-angular": "^0.803.5", "@angular/cli": "~8.3.5", "@angular/compiler-cli": "^8.2.7", "@angular/language-service": "^8.2.7", "typescript": "~3.6.3" }Por ejemplo, ~3.6.3 implica que podemos subir hasta una versin minor (3.7.x), pero no ms (no a la 3.8.1 por ejemplo). El modificador ^8.2.7, implica que podemos subir todas las versiones minor y patch que necesitemos, pero no actualizaremos la versin major a 9.0.0 por ejemplo.Para ms informacin pueden leer el componente de node que trabaja el versionado semntico.package-lock.jsonMientras que el package.json permite configurar las dependencias para un rango de versiones posibles, el package-lock.json es la foto de las dependencias exactas que se descargaron en tu mquina, incluyendo las dependencias indirectas.Esto permite que todos los desarrolladores (y especialmente el CI) puedan replicar el mismo entorno y que las versiones que instalamos no dependa del momento en el que hacemos npm install.Primera instalacin con npm installLa primera vez que descargamos un proyecto, debemos descargar las dependencias, para eso debemos ejecutarnpm installSi existe el archivo package-lock.json, npm partir de esa definicin para ir a buscar las dependencias y bajarlas a nuestro directorio node_modules. Si no existe el archivo package-lock.json, entonces se basar en las definiciones del package.json para buscar las ltimas versiones posibles de cada uno de los componentes.Tengo que versionar el package-json? (subirlo a git)TL;DR S.La justificacin es que de esa manera estaremos seguros de que todos los que trabajamos en el proyecto tengamos las mismas dependencias.Actualizando nuestras dependenciasPara mantener al da las dependencias de nuestros ejemplos, tenemos dos opciones:Subir las versiones minor - npm updatePodemos detectar si hay nuevas versiones minor que no rompan la retrocompatibilidad escribiendo en nuestra consola o git bash:npm outdatedO directamente podemos escribir:npm updateAl ejecutar este comando: se actualiza el package-lock.json y tambin en el directorio node_modules descargamos los paquetes con el cdigo que vamos a utilizarSubir las versiones major (con coraje)Si ests seguro que vas a poder seguir manteniendo estable tu conjunto de dependencias, pods trabajar con npm-check-updates. Lo instals globalmente la primera vez:npm install -g npm-check-updatesY luego lo ejecutsncu -uEsto te va actualizar las versiones de tu package.json tratando de subir a la mayor versin posible. Luego pods correr npm update (o bien npm install si te bajaste el proyecto la primera vez)" + +} , + +{ + +"title" : "Objective c", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/objective-c.html", +"date" : "", +"content" : "Sobre el lenguaje Objective C (wikipedia) Programming with Objective CHerramientas basadas en Objective C: Apple Developer Libraries Apple OS X Apple iOS" + +} , + +{ + +"title" : "Observer en pharo smalltalk", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/observer-en-pharo-smalltalk.html", +"date" : "", +"content" : "ResumenEl mecanismo de observer es as: Hay un observador (que entiende el mensaje update:, y hay que implementarlo) Hay un observado (que entiende los mensajes changed: y addDependent:, que no hay que implementar pero s usar)InicializacinAl inicializar todo (antes de que empiece a funcionar) tens que hacer:observadoaddDependent:observador.UsoDespus, el observado necesita avisar que l mismo cambi, y eso lo hace con:selfchanged:#variableQueCambiPharo mgicamente le va a mandar el mensaje update: #variableQueCambio a todos sus observadores. Entonces, en cada observador tens que definir el mtodo:update:nombreDeLoQueCambio"achagoloqueseaquequierahacerelobserver."Algo comn para hacer ah es chequear si me interesa ese nombreDeLoQueCambio, bien hacerle preguntas a mi observado (que me guard de antemano).Diagrama de Clases" + +} , + +{ + +"title" : "Objetos factory - instanciando objetos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/oo-objetos-factory.html", +"date" : "", +"content" : "IntroduccinInstanciar objetos no siempre resulta fcil, especialmente en los tests, cuando debemos tener en cuenta: valores por defecto para esa clase de equivalencia configuraciones para algunos tests especficos tratando siempre de que sea fcil de usar y no repetir cdigoPor ejemplo, necesitamos definir una computadora que tiene 16 GB de RAM y un disco HDD de 2048, con mouse, en base a esta definicin:class SSD { method precio() = 500 method estaCopado() = true}class HDD { var property tamanio = 1024 // expresado en GB method precio() = if (tamanio &gt; 1024) 400 else 250 method estaCopado() = tamanio &gt; 1024}class Memoria { var property tamanio // expresado en GB method precio() = tamanio / 10 method estaCopada() = tamanio &gt; 16}class Computadora { var memoria var disco = new HDD() var mouse = true method precio() = memoria.precio() + disco.precio() + 1000 method estaCopada() = memoria.estaCopada() || disco.estaCopado()}Clases de equivalencia para el precioLas clases de equivalencia para el precio se forman en base a diferentes configuraciones de computadoras ssd, no importa la memoria hdd de ms de 1TB, no importa la memoria hdd de 1TB, no importa la memoria hdd de menos de 1TB, no importa la memoriaLa presencia o no del mouse no juega ningn papel, y realmente tampoco la memoria que calcula siempre el mismo valor.Clases de equivalencia para estaCopadaEn cambio, las clases de equivalencia que configuran a una computadora copada son: computadora con ssd, no importa la memoria (copada) computadora con hdd de ms de 1TB, no importa la memoria (copada) computadora con hdd de 1TB, memoria de 16 (no copada - caso borde en ambas configuraciones) computadora con menos de 1TB, memoria ms de 16 (copada) computadora con menos de 1TB, memoria de menos de 16 (no copada)Unificando las clases de equivalenciaAhora vemos que si intersectamos las clases de equivalencia para precio y estaCopada, las primeras 4 de estaCopada coinciden con las de precio, por lo tanto vamos a tener que buscar estas configuraciones: var computadoraConSsd = new Computadora() var computadoraConPocoHdd = new Computadora(disco = new HDD(tamanio = 512)) var computadoraComun = new Computadora(disco = new HDD(tamanio = 1024)) var computadoraConMuchoHdd = new Computadora(disco = new HDD(tamanio = 2048))Dnde lo implementamosLas opciones son varias: en cada test configuramos la computadora que necesitamos: eso tiene la desventaja de que si es necesario resolver la inicializacin en ms pasos, se empezarn a repetir en cada uno de los tests. lo ubicamos en el describe como variables, eso tiene dos desventajas: a) los tests tienen pocas variables compartidas entre s (baja cohesin), no es fcil ver qu tests usan qu variables y la inicializacin tambin est lejos del momento en que se prueban, y b) cada vez que corremos un test se evalan todas las expresiones del describe, por lo que hay una penalizacin en performance. delegar en otro objeto la inicializacin de las clases de equivalencia que necesitamos, algo comoobject computadoraFixture { method computadoraConSSD() = new Computadora() method computadoraConPocoHdd() = new Computadora(disco = new HDD(tamanio = 512)) method computadoraComun() = new Computadora(disco = new HDD(tamanio = 1024)) method computadoraConMuchoHdd() = new Computadora(disco = new HDD(tamanio = 2048))}Es decir, tenemos un objeto que nos ayuda a crear otros objetos, lo que podramos llamar objetos factory (fabrican configuraciones de objetos que nosotros necesitamos frecuentemente).Ventajas en el mantenimientoEl costo que pagamos es mantener una nueva abstraccin, la ventaja es que si la computadora tuviera ahora una lista de dueos:object juan { method esCopado() = ...}object ceci { method esCopado() = ...}class Computadora { var memoria var disco = new HDD() var mouse = true const duenios = [] method precio() = memoria.precio() + disco.precio() + 1000 method agregarDuenio(duenio) { duenios.add(duenio) } method estaCopada() = memoria.estaCopada() || disco.estaCopado() || duenios.any { duenio =&gt; duenio.esCopado() }}Y necesitramos agregar en la computadora comn a dos dueos, solo debemos modificar un mtodo: method computadoraComun() { const compu = new Computadora(disco = new HDD(tamanio = 1024)) compu.agregarDuenio(ceci) compu.agregarDuenio(juan) return compu }Tambin podramos hacer que los otros mtodos se llamen entre s para agregar los duenios:method computadoraConMuchoHdd() { const compu = self.computadoraComun() compu.disco(new HDD(tamanio = 2048)) return compu}Esto tambin podemos hacerlo con la variante del fixture, solo que cada vez que ejecutemos cada test se evaluarn todos los mtodos." + +} , + +{ + +"title" : "Temporary variables", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/oo-temporary-variable.html", +"date" : "", +"content" : "Introduccin: persona instrudaSupongamos que tenemos que conocer si Helmut es una persona instruida, esto ocurre cuando ley ms de 20 libros y conoce ms de 3 idiomas.Tenemos esta implementacin:object helmut { var librosLeidos = 0 const idiomasQueConoce = [] method leerLibro() { librosLeidos = librosLeidos + 1 } method conocerIdioma(idioma) { idiomasQueConoce.add(idioma) } method esInstruido() ...}Bad smell: temporary variableEs un patrn frecuente la resolucin del ejemplo agregando un nuevo atributo en helmut:object helmut { ... var instruido = false method esInstruido() = instruido}Una solucin similar puede ser definir instruido como una property, el efecto es el mismo. Esto tiene algunas desventajas: el problema no es tanto incorporar un nuevo atributo, sino que es un atributo que podra calcularse y que adems tiene dependencias con las otras dos variablesPara mantener consistente el estado de Helmut, deberamos codificar su comportamiento de la siguiente manera:object helmut { var librosLeidos = 0 const idiomasQueConoce = [] var instruido = false method leerLibro() { librosLeidos = librosLeidos + 1 // sincronizo esInstruido... instruido = librosLeidos &gt; 20 &amp;&amp; idiomasQueConoce.size() &gt; 3 } method conocerIdioma(idioma) { idiomasQueConoce.add(idioma) // sincronizo esInstruido... instruido = librosLeidos &gt; 20 &amp;&amp; idiomasQueConoce.size() &gt; 3 } method esInstruido() = instruido}Por supuesto, podemos extraer un mtodo aparte, igualmente estaremos enviando el mismo mensaje en ambos casos:object helmut { ... method leerLibro() { librosLeidos = librosLeidos + 1 self.actualizoInstruido() } method conocerIdioma(idioma) { idiomasQueConoce.add(idioma) self.actualizoInstruido() } method actualizoInstruido() { instruido = librosLeidos &gt; 20 &amp;&amp; idiomasQueConoce.size() &gt; 3 } ...}Otra variante similar consiste en que el mtodo instruido haga algo como:method leerLibro() { librosLeidos = librosLeidos + 1 self.esInstruido()}method conocerIdioma(idioma) { idiomasQueConoce.add(idioma) self.esInstruido()}method esInstruido() { instruido = librosLeidos &gt; 20 &amp;&amp; idiomasQueConoce.size() &gt; 3 return instruido}lo cual agrega ms desventajas: la variable instruido da lo mismo si es una variable de instancia (atributo) o una variable local del mtodo esInstruido, solo se asigna para ser retornada mtodos que representan acciones como leer el libro o conocer idioma, llaman a una aparente pregunta (esInstruido) solo para actualizar el estado, se confunde as mtodos que tienen efecto y que no lo tienen si hay ms atributos cuyos valores dependen de otros, puede no resultar trivial el momento de actualizar el estado del objeto sin que quede momentneamente inconsistente (o puede resultar en errores si no respetamos el orden en que actualizamos dichos atributos) En general, intentar guardarse cosas que pueden ser calculadas es un smell, conocido tambin como precalcular, trmino popularizado por Maese Rasta.Una alternativa ms simpleLa alternativa ms sencilla es descartar todos los atributos que pueden calcularse, de esa manera evitamos sincronizar el estado de Helmut:object helmut { var librosLeidos = 0 const idiomasQueConoce = [] method leerLibro() { librosLeidos = librosLeidos + 1 } method conocerIdioma(idioma) { idiomasQueConoce.add(idioma) } method esInstruido() = librosLeidos &gt; 20 &amp;&amp; idiomasQueConoce.size() &gt; 3}Aqu vemos cmo tenemos mtodos que producen efecto (acciones): leerLibro, conocerIdioma y mtodos que no tienen efecto (contestan preguntas): esInstruidoHeurstica para tener atributos que pudieran ser calculablesEn general, intentar guardarse cosas de antemano para optimizar es un smell. Como dijo Donald Knuth, premature optimization is the root of all evil.Sin embargo, s hay ocasiones donde guardarse un resultado de antemano es aceptable: si el clculo lleva tiempo (o implica acceder a recursos externos costosos, como un archivo o un servicio web) si la tasa de actualizacin es poco frecuente pero necesitamos conocer esa informacin una gran cantidad de veces al dason seales en los que tener un clculo como atributo es justificable, algo que es improbable que ocurra en cursos iniciales de programacin OO." + +} , + +{ + +"title" : "Orden superior y diseno", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/orden-superior-y-diseno.html", +"date" : "", +"content" : "Ver tambin Orden SuperiorUnaconsecuenciadeimplementarelpasajedefuncionescomoargumentosenlenguajesorientadosaobjetos#esqueelenvodemensajesdesdeunobjetohaciaotroocurreendosmomentos:Un objeto A enva el mensaje de orden superior a otro B, pasando por argumento un bloque de cdigo El objeto receptor B enva un mensaje al bloque de cdigo, que es evaluado, potencialmente, enviando mensajes a objetos que slo A conoca.Es decir, mientras que en la programacin imperativa el cdigo cliente llama es aquel que llama a la biblioteca, aqu es la biblioteca quien termina llamando al cdigo cliente, lo que se conoce como Inversin de Control (IoC).object PruebaIoC {defsumaDeInversas(valores:List[Int])=valores.map{1/_}.sum}scala&gt; PruebaIoC.sumaDeInversas( List(4,0,6) )java.lang.ArithmeticException: / by zeroatPruebaIoC$$anonfun$sumaDeInversas$1.apply$mcII$sp(:8)atPruebaIoC$$anonfun$sumaDeInversas$1.apply(:8)atPruebaIoC$$anonfun$sumaDeInversas$1.apply(:8)atscala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)atscala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)atscala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)atscala.collection.immutable.List.foreach(List.scala:45)atscala.collection.TraversableLike$class.map(TraversableLike.scala:194)atscala.collection.immutable.List.map(List.scala:45)atPruebaIoC$.sumaDeInversas(:8).. Se pierde la secuencialidad El control queda en manos de la biblioteca, que se constituye en un motor responsable de evaluar el cdigo -&gt; ganamos en declaratividad el codigo puede ser evaluado de forma diferente a la planteada por el cliente, incluso de forma diferida, asincrnica o ignorado completamenteevaluacion diferida mediante thunks" + +} , + +{ + +"title" : "Orden superior", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/orden-superior.html", +"date" : "", +"content" : "GeneralidadesLlamamos a una determinada operacin de orden superior si la misma recibe otra operacin (comportamiento) por parmetro, siendo capaz de ejecutarla internamente.Al usar orden superior tenemos las siguientes ventajas: Puedo aislar y reutilizar comportamiento comn. Puedo partir mi problema, separando responsabilidades, entre el cdigo que tiene orden superior, y el comportamiento parametrizado. Puedo tener un cdigo con partes incompletas, esperando rellenarlos pasando comportamiento por parmetro, y no slo datos. Puedo generar abstracciones ms jugosas! Ms all de las abstracciones de orden superior que ya me proveen los lenguajes, la mayora de los mismos me dan la posibilidad de armar mi propio comportamiento de orden superior (En la materia lo vemos en Haskell ms directamente, aunque se puede tambin en SWI-Prolog). Con abstracciones ms adecuadas, con responsabilidades repartidas, y sin repeticin de lgica, genero un cdigo ms expresivo (porque en general es ms fcil de leer), y ms declarativo (porque en general al usar orden superior oculto detalles algortmicos)Paradigma FuncionalTanto en matemtica como en informtica, se definen las funciones de orden superior como funciones que reciben funciones por parmetro o bien devuelven una funcin como resultado.La funcin filter (en haskell y otros lenguajes funcionales) es un ejemplo comn de este tipo de funciones ya que recibe por parmetro una funcin f y una lista y retorna una nueva lista que contiene aquellos elementos que al ser aplicados como parmetros a f devuelven verdadero. La funcin f debe tener entonces aridad 1 y devolver un valor booleano.filter::(a -&gt; Bool)-&gt;[a]-&gt;[a]Otras funciones comunes son map, fold, funciones de ordenamiento o bsqueda, composicin de funciones (.), flip, etc (pueden consultar sus tipos en el intrprete con :t).Ejemplos comunes del anlisis matemtico que es ms difcil de ver en los lenguajes de programacin son la derivada y la integral (Vemos al proceso de derivar como una funcin que recibe otra funcin cualquiera y devuelve su derivada).En el Clculo lambda no tipado todas las funciones son de orden superior. En el clculo lambda con tipado, desde el cual la mayora de los lenguajes funcionales se derivan, las funciones de orden superior son generalmente aquellas cuyos tipos de parmetros contienen una o ms flechitas.En matemtica a las funciones que retornan funciones se las conoce como operadores o functionals. Un ejemplo comn es el clculo derivativo, ya que mapea una funcin a otra funcin.La aplicacin parcial es tambin orden superior?En primer lugar, recordemos que en Haskell las funciones estn currificadas. La Aplicacin Parcial no es una funcin, lo que s podemos analizar es la Aplicacin y lo importante es qu recibe y qu devuelve, eso se ve cuando se analiza el tipo de la funcin. Existe una funcin que nos va a servir para realizar este anlisis llamada $ que lo que hace es aplicarle un parmetro a una funcin.($)::(a -&gt; b)-&gt;a-&gt;b($)funcionparametro=funcionparametroSi el primer parmetro de la funcin $ es una funcin de aridad mayor a 1 (por ejemplo, mod) y la aplicamos de la siguiente forma:mod$10El resultado ser una funcin:mod$10::Integrala=&gt;a -&gt; aLa aplicacin, entonces es una funcin de orden superior ya que recibe una funcin por parmetro y si la misma no queda totalmente aplicada tambin retorna una funcin.Paradigma LgicoDecimos que un predicado es de Orden Superior si este recibe como argumento una consulta a otro/s predicado/s. Algunos ejemplos son not, findall y forall.Hacer nuestros propios predicados de orden superior en Prolog no es tan natural como resulta en Haskell, lo cual se desprende de que los predicados y consultas no son valores, sin embargo Prolog nos permite hacerlo mediante el predicado call.Paradigma EstructuradoEn el paradigma estructurado, una porcin de cdigo puede alcanzar resultados algortmicos como si fuesen obtenidos a travs de funciones de orden superior, ejecutando cdigo dinmicamente (a veces denominadas operaciones Eval o Execute) durante la evaluacin. Desafortunadamente hay limitaciones al alcance del mismo: El cdigo en el argumento a ser ejecutado usualmente no posee tipado esttico; estos lenguajes generalmente dejan relegado al tipado dinmico la determinacin de la seguridad y la buena disposicin del cdigo a ser ejecutado. El parmetro es usualmente provisto como un String, cuyo valor no puede ser conocido hasta el momento de ejecucin. Este string debe ser o bien compilado durante la ejecucin del programa (usando compilacin just-in-time) o bien evaluado durante la interpretacin, causando un overhead adicional y usualmente generando cdigo menos eficiciente. Tambin pueden ser utilizadas Macros para lograr algunos de los efectos del orden superior. No obstante ello, estas macros no pueden evitar fcilmente el problema de la captura de variables; tambin resultan en grandes cantidades de cdigo duplicado, el cual puede ser ms difcil de optimizar para un compilador. Generalmente las Macros no son fuertemente tipadas, aunque pueden producir cdigo fuertemente tipado.Si les interesa profundizar en el uso de orden superior en el lenguaje C, pueden leer el siguiente apunte realizado por ayudantes de la ctedra.Y los objetos?Esta me gust ms, ah vamos, en objetos no tiene sentido reconocer ordenes, porque lo natural es que si la operacion es el mensaje (recordar valores y operaciones), entonces tanto el receptor del mensaje como los parametros son siempre objetos.Entonces, estoy estudiando para el final, que tengo que entender: que es eso de orden: un X que puede admitir otro X como parametro. digo que reconozco dos ordenes, si eso es una caracterstica especial que quiero remarcar, si no lo que pasa es que no tiene sentido la distincin de rdenes en este contexto para cada paradigma: si tiene sentido decir algo asi como orden superior, y en que casos para qu uso la idea superior, en particular en funcional. Una vez que entendi eso, que herramienta que vimos de Wollok me sirve para un propsito similar. En Haskell: filter (&gt;3) unaLista En Wollok: unaLista.filter({elemento =&gt; elemento &gt; 3}) Est claro que ambos ejemplos sirven para lo mismo, pero qu es lo que recibe por parmetro el filter de la solucin objetosa? Es un bloque, y los bloques son objetos.En general no aplicamos el concepto de orden superior a los objetos porque si la definicin fuera un obeto que recibe otro objeto por parmetro eso incluye a todos los objetos que reciban algn parmetro en algn mensaje porque. todos son objetos. Pods pensar que todos son de orden superior, si prefers, pero no pods clasificar a los objetos en rdenes.Por otro lado me gustara disentir con la idea de relacionar muy fuertemente a los bloques con orden superior, es cierto que estoy pasando comportamiento por parmetro. Pero, como deca, eso pasa muchas veces en objetos, entonces hacer una mencin especial a los bloques no me parece. En algn momento nosotros mismos lo contamos en esos trminos, pero bueno, evolucionamos. Igualmente esa respuesta no se considerara errnea en un final, pero s quiero comenzar a transmitirla de esta forma que me parece ms adecuada.Creo que la diferencia del bloque con el resto de los objetos es la creacin de comportamiento ad-hoc, para un fin especfico, los uso una sola vez y no les pongo nombre. Ese efecto se asemeja a otros elementos del funcional, como ser las Expresiones lambda o la Aplicacin Parcial, que me permiten armar en el aire funciones con esas caractersticas (fjense que tambin pasa en funcional, que las expresiones lambda o la aplicacin parcial son tiles para combinarlas con las funciones de orden superior).Volviendo al tema principal, el chiste del orden superior es que yo paso algo ms complejo que un nmero, una lista o una estructura (functor, tupla, etc) por parmetro. Al pasar un predicado o funcin yo paso comportamiento por parmetro, el conocimiento de cmo resolver el problema ahora no se divide en datos y algoritmo, sino que la funcin de orden superior tiene parte del algoritmo y la otra parte viene por parmetro. (Ntense las comillas al usar las palabras algoritmo y comportamiento en los paradigmas declarativos.) Eso le da un poder muy piola a lo que construimos. En fin, cmo llevamos eso de nuevo a objetos? Yo creo que se aprovechan beneficios similares a los del orden superior en el momento en que los objetos que interactan (el receptor del mensaje y el parmetro) tienen dividido el comportamiento en esa forma, es decir, que el objeto receptor le pide al otro cosas que no sean solamente devolver un dato sino que tengan otra complejidad. Claro, cuando uso un bloque eso pasa siempre, y por eso es tentador establecer la relacin. Pero si abrimos un poco la cancha, creo que es fcil ver que ocurre casi siempre que tengamos delegacin y responsabilidades bien repartidas.Links Relacionados Lambdas en Java 8 Introduction to higher-order functions Higher-order function Closures and Higher-Order Functions Higher-order functions and variational calculus Boost Lambda Library for C++" + +} , + +{ + +"title" : "Otros temas interesantes de programacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/otros-temas-interesantes-de-programacion.html", +"date" : "", +"content" : " Mnada Parsers Mondicos Lenguajes Especficos de Dominio Desarrollo de Interfaces Grficas en Haskell Git, un versionador distribuido" + +} , + +{ + +"title" : "Pagina principal", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/pagina-principal.html", +"date" : "", +"content" : "a" + +} , + +{ + +"title" : "Palitos de queso", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/palitos-de-queso.html", +"date" : "", +"content" : "Ingredientes 100 grs de queso rallado 100 grs de pan rallado 100 grs de harina 100 grs de manteca 1/2 cucharadita de salPasos: Mezclar todo en un bol hasta que quede una masa semi dura. Agregando agua FRIA si hace falta (muy muy poquito) Estirarla a 0.5cm de grosor y cortar en palitos de 1cm de ancho por 5cm de largo Arrolarlos con la palma de la mano y ponerlos sobre placa enmantecadas y enharinadas Cocinarlos en horno templado hasta que tomen colorNOTA: Cuando se enfran se endurecen, as que al sacarlos del horno deben estar un poquito blandos" + +} , + +{ + +"title" : "Panqueques", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/panqueques.html", +"date" : "", +"content" : "Cantidad: 14 panquequesIngredientes: 1 taza de harina (120gr) 1 cucharadita de polvo de hornear 1/4 de cucharadita de sal 2 huevos 1 taza de leche 30 grs de manteca derretida Esencia de vainillaPasos: Tamizar juntos la harina, el polvo de hornear y la sal. Aparta batir los huevos y se les agrega la leche y la manteca derretida Se vierte esta mezcla sobre los ingredientes secos y se bate hasta que el batido quede liso Se le puede agregar un poco de esencia de vainilla Se calienta una sarten con un poquito de manteca y ponen 1 cucharn del batido para que cubra toda la sarten Se cuece a fuego moderado hasta que tome color y luego se lo da vuelta para cocer el otro lado Si es para comer dulces, se los puede espolvorear con azcar apenas se los saca de la sarten Repetir hasta que se acabe el batido." + +} , + +{ + +"title" : "Paradigma de objetos method lookup", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-de-objetos---method-lookup.html", +"date" : "", +"content" : "Tambin conocido como Dynamic dispatchEs el mecanismo por el cual se relaciona el envo de un mensaje con la ejecucin de un mtodo determinado.Con objetos individualesCuando definimos un objeto y le declaramos su propio comportamiento, este mecanismo es trivial. Si existe un mtodo que se llame igual que el mensaje definido y con la misma cantidad de parmetros, se ejecutar ese mtodo, de lo contrario tirar un error porque no entiende el mensaje (a menos que se trate de un mensaje bsico como la igualdad o identidad que cualquier objeto entiende).Con clases y herencia simpleQu pasa cuando a un objeto i instancia de la clase C se le enva un mensaje de nombre m?Tenemos (a efectos de entender el mecanismo porque esto lo hace internamente el ambiente) que mantener una referencia a la clase donde estamos buscando en un momento determinado.Al principio la clase actual es C y el objeto receptor del mensaje (self) es i.El algoritmo es el siguiente:1. se busca en la clase actual un mtodo con el nombre m1a. si se encuentra se ejecuta el mtodo encontrado; se ejecuta el mtodo en el objeto i y se termin el method lookup1b. si no se encuentra y la clase actual no es Object la clase actual pasa a ser la superclase de la clase actual y se vuelve a 1.1c. si no se encuentra y la clase actual es Object entonces el objeto i no entiende el mensaje mEl comportamiento por defecto cuando un objeto no entiende un mensaje es lanzar un error.Ejemplo 1Si le enviamos el mensaje asUppercase al objeto 'hola' (o sea, al string 'hola') qu debera pasar?Asumamos (porque no es as) que 'hola' es instancia de String, que String es subclase de Collection y que Collection es subclase de Object.Siguiendo el algoritmo de arriba a travs de los pasos indicados con -i es 'hola'clase actual es Stringm es #asUppercase- se busca en String un mtodo con el nombre #asUppercase- se encuentra el mtodo #asUppercase en la clase String- se ejecuta el mtodo #asUppercase de la clase String sobre i el objeto receptor del mensaje (o sea hola)Conclusin: 'hola' entiende el mensaje #asUppercaseEjemplo (heredando un mtodo)Basndonos en el ejemplo 1, si le enviamos el mensaje == al objeto 'hola' (o sea, al string 'hola') qu debera pasar?i es 'hola'clase actual es Stringm es #==- se busca en String un mtodo con el nombre #==- no se encuentra el mtodo #== en String y la clase actual no es Object entonces la clase actual pasa a ser Collection (la superclase de la clase actual) y se vuelve a 1.- se busca en Collection un mtodo con el nombre #==- no se encuentra el mtodo #== en Collection y la clase actual no es Object entonces la clase actual pasa a ser Object (la superclase de la clase actual) y se vuelve a 1.- se busca en Object un mtodo con el nombre #==- se encuentra el mtodo #== en la clase Object- se ejecuta el mtodo #== de la clase Object sobre i, el objeto receptor del mensaje (o sea hola)Conclusin: 'hola' entiende el mensaje #==Ejemplo (no entiende el mensaje)Basndonos en el ejemplo 1, si le enviamos el mensaje factorial al objeto 'hola' (o sea, al string 'hola') qu debera pasar?i es 'hola'clase actual es Stringm es #factorial- se busca en String un mtodo con el nombre #factorial- no se encuentra el mtodo #factorial en String y la clase actual no es Object entonces la clase actual pasa a ser Collection (la superclase de la clase actual) y se vuelve a 1.- se busca en Collection un mtodo con el nombre #factorial- no se encuentra el mtodo #factorial en Collection y la clase actual no es Object entonces la clase actual pasa a ser Object (la superclase de la clase actual) y se vuelve a 1.- se busca en Object un mtodo con el nombre #factorial- no se encuentra y la clase actual es Object entonces el objeto i no entiende el mensaje mO dicho de otra forma, 'hola' no entiende el mensaje #factorial" + +} , + +{ + +"title" : "Paradigma de objetos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-de-objetos.html", +"date" : "", +"content" : "Un objeto es un ente computacional que exhibe comportamiento (podemos comunicarnos con l mediante mensajes) y puede (o no) tener un estado interno (referencias a otros objetos).Un programa basado en este paradigma es un conjunto de objetos que interactan entre s en un ambiente mandndose mensajes para lograr un objetivo determinado.IntuicinIntuitivamente, nuestra realidad parece estar conformada por muchos objetos: automviles, mesas, frascos de mermelada, papeles, computadoras, cables. Esos objetos estn all, se pueden diferenciar entre ellos: una mesa y una silla son diferentes. Ms importante an, si tengo dos sillas, aunque hayan sido fabricadas en el mismo lugar, tengan la misma cantidad de patas y mismo tapizado, las puedo distinguir. Es decir, aunque dos objetos se vean muy parecidos, siguen siendo dos objetos diferentes! Los objetos se pueden diferenciar, porque tienen identidad propia.Y por qu nos interesan los objetos? Cuando programamos, queremos resolver problemas, entonces no nos van a interesar tanto los objetos por s mismos, sino que estos pueden resolver problemas. Cmo es esto de resolver problemas? Simple: las hojas de papel nos sirven para escribir en ellas, los cables para conducir energa, los automviles, para transportarnos. Es decir, no nos va a interesar la mesa porque tenga cuatro patas y una tabla de madera, sino porque esas cuatro patas y tabla nos permitirn resolver el problema de apoyar nuestro almuerzo. De los objetos, entonces, nos va a interesar que son capaces de hacer cosas: tienen comportamiento.Hay algo ms que es interesante en los objetos: a veces estos cambian con el tiempo. Por ejemplo, las mesas se deterioran despus de servir de sostn por mucho tiempo, el frasco de mermelada se vaca despus de sacarle mermelada varias veces, el automvil pierde nafta cuando se mueve, y gana nafta cuando se lo recarga. Los objetos pueden tener un estado, y el mismo puede cambiar.Entonces parece que la pregunta de qu es un objeto se responde fcil es una cosa, pero no cualquier cosa: tiene identidad, estado y comportamiento.Ahora nos queda realizar un ltimo salto: en realidad hay ms cosas, ms objetos en nuestro mundo, que slo automoviles, hojas o mesas. Hay por ejemplo, pases, culturas,trabajos, problemas, ideas, sentimientos. Y una idea se puede diferenciar de otra (identidad), un trabajo puede resolverlos el problema de tener dinero a fin de mes (comportamiento), y un pas puede cambiar (estado). Los objetos, entonces, pueden ser tambin cosas que no podemos tocar: cosas intangibles.El paradigma de objetos nos propone justamente resolver nuestros problemas usando, adivinen..objetos!. Y para eso, tendremos que zambullirnos en un mundo de objetos.Teora Mensajes y mtodos Referencias: Variables y Pseudovariables Encapsulamiento Polimorfismo Modelando objetos - Responsabilidades y delegacin Manejo de errores Prototipado Clases Prototipado vs Clases Herencia Method lookup Redefinicin Composicin (OOP) Herramientas de instanciacin vs. Mtodos de clase Igualdad vs. Identidad Inmutabilidad Garbage collector BloquesColecciones Intro a colecciones Sabores de colecciones Mensajes de colecciones DiccionariosCosas que pueden servir para pensar en cmo modelar un enunciado Diferencia entre objetos y procedural - con un ejercicio de la gua 1 Nombres de clases Ley de demeter Cuestiones bsicas para resolver el parcial de objetos Puntos de entradaUn poco ms sobre Smalltalk Sintaxis de Smalltalk Tipos de mensajes en Smalltalk Variables locales en mtodos Precedencia de Mensajes Manejo de booleanos min: y max: Variables y mtodos de clase Arrays literales en Smalltalk Preguntas Frecuentes Mtodos de clase para crear objetos inicializados Cmo hacer para que de un objeto muestre lo que yo quiero Tutorial de Squeak y Pharo Cmo crear una subclase en Squeak Testing Pharo para programadores OzonososMiscelnea Mquina Virtual Diagrama de clases Lenguajes Wollok" + +} , + +{ + +"title" : "Paradigma de programacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-de-programacion.html", +"date" : "", +"content" : "Un paradigma de programacin es un marco conceptual, un conjunto de ideas que describe una forma de entender la construccin de programa, como tal define: Las herramientas conceptuales que se pueden utilizar para construir un programa (objetos, relaciones, funciones, instrucciones). Las formas vlidas de combinarlas.Los distintos lenguajes de programacin proveen implentaciones para las herramientas conceptuales descriptas por los paradigmas. Existen lenguajes que se concentran en las ideas de un nico paradigma as como hay otros que permiten la combinacin de ideas provenientes de distintos paradigmas.Dado que un paradigma es un conjunto de ideas, su influencia se ve principalmente en el momento de modelar una solucin a un problema dado. No es suficiente saber en qu lenguaje est construido un programa para saber qu marco conceptual se utiliz en el momento de construirlo. El paradigma tiene ms relacin con el proceso mental que se realiza para construir un programa que con el programa resultante.Qu es un programa?Para definir programa es necesario analizarlo desde dos diferentes perspectivas. Uno de esos puntos de vista es anlogo al del usuario del programa, interesado en la tarea que realizar el programa. Desde esa perspectiva un programa es aquello que permite que una computadora realice una tarea determinada.El otro punto de vista es el de aquel que tenga que construir o modificar ese programa (programador), a quien interesar tambin la forma en que est construido. Desde esta perspectiva no hay una nica definicin al concepto de programa ya que cada paradigma ofrece una respuesta distinta a esta pregunta.Paradigma EstructuradoSecuencia ordenada de instrucciones que manipulan un espacio de memoria.Paradigma de ObjetosConjunto de objetos que se conocen entre s a travs de referencias y se envan mensajes en un ambiente.Paradigma LgicoConjunto de predicados definidos a travs de clusulas (hechos y reglas) que describen propiedades y relaciones de un conjunto de individuos, sobre los cuales podemos realizar consultas.Paradigma FuncionalConjunto de funciones (relaciones que cumplen las propiedades de unicidad y existencia), que pueden ser evaluadas para obtener un resultado.Otras Ideas Modelar la realidad, o mejor dicho que el programa se acerque a la realidad (vs. tener un diseo y luego un programa lejano a eso)" + +} , + +{ + +"title" : "Paradigma funcional", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-funcional.html", +"date" : "", +"content" : "IntroduccinEste paradigma se basa en un conjunto de funciones (relaciones que cumplen las propiedades de unicidad y existencia), que pueden ser evaluadas para obtener un resultado. El paradigma funcional est basado en conceptos que vienen de la matemtica, entonces algunas cosas (p.ej. notaciones en el lenguaje) estn sacadas de lo que aprendimos en Anlisis I / lgebra / Discreta.Conceptos generales Concepto de funcin Aplicacin Pattern Matching en Haskell Composicin Aplicacin Parcial Orden Superior Currificacin Inmutabilidad Funciones por Partes Lazy Evaluation Recursividad en HaskellTipos Tipos de Haskell Typeclasses Inferencia de tipos Polimorfismo paramtrico y ad-hoc Notacin point-free: Cuntos parmetros espera una funcin? Data: Definiendo nuestros tipos en HaskellExtras simpticos Definiciones locales (where) Expresiones lambda Listas por comprensinErrores comunes Errores comunes al comenzar a trabajar con Haskell Cundo usar parntesis Problemas comunes con los tipos numricos de Haskell &lt;- Entr ac si tens problemas con la divisin (/) Unexpected ;? possibly incorrect indentation or mismatched brackets Hugs.Trex.insertField not in scope cannot construct the infinite type Tips para aprobar un parcial de funcionalPara aprender ms sobre el lenguaje Haskell Learn You a Haskell for Great Good! (Ac en espaol) Todo lo que ud deseaba saber de Haskell y ms (Por Stephen Diehl) Wiki Funciones que trae por defecto (Prelude)Problemas complejos y cosas locasAc hay algunas cosas interesantes que escapan al nivel de funcional que se espera que aprendan para Paradigmas, si te interesa profundizar en el tema es muy interesante! Mnadas, Monadas, y Functores en Haskell: Functors, Applicatives, And Monads In Pictures" + +} , + +{ + +"title" : "Paradigma logico casos de no inversibilidad", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---casos-de-no-inversibilidad.html", +"date" : "", +"content" : "IntroduccinLos casos de no inversibilidad, y algunos de no funcionamiento o respuestas incorrectas, estn relacionados con variables que no estn ligadas en cierto punto (recordando que el anlisis debe hacerse de izquierda a derecha) y deben estarlo, o (menos probable) al revs, variables que deben llegar a cierto punto sin ligar y estn ligadas.Veamos varios casos, que incluyen todos los casos de no-inversibilidad que vemos en la materia.Hechos con variablesPor lo general aquellos predicados definidos en base a hechos no suelen ser problemticos, porque lo normal es que incluyan informacin sobre los individuos a los cuales se refieren. Sin embargo, el siguiente es un hecho vlido que no es inversible para su segunda aridad:leGusta(pepe,_).Eso dice que a pepe le gusta cualquier cosa, sin acotar de ninguna forma qu podra ser aquello que le gusta. Para hacer el predicado inversible, deberamos acotar qu puede ser aquello que le gusta convirtindolo en una regla, por ejemplo:leGusta(pepe,Comida):-comida(Comida).NegacinNegacin: las variables que aparecen en la parte de la clusula deben llegar ligadas, a menos que sean variables afectadas por un para ningn, en este caso deben llegar libres. P.ej. esta definicin del predicado esPlantaComestibleesPlantaComestible(Planta):-not(esVenenosa(Planta)).no es inversible, porque Planta debe estar ligada antes de llegar al not. Por qu? Ver Paradigma Lgico - negacinPara hacer al predicado inversible, generamos el dominio de la variable PlantaesPlantaComestible(Planta):-esPlanta(Planta),not(esVenenosa(Planta)).Aritmtica**Aritmtica: ** todas las variables a la derecha del is deben llegar ligadas al is. P.ej. el predicado precioPorCantidad definido asprecioPorCantidad(Planta,Cantidad,PrecioTotal):-precioPlanta(Planta,Precio),PrecioTotalisCantidad*Precio.no es inversible para el 2do argumento, porque si no se indica un nmero para Cantidad en la consulta, al llegar a la cuenta hay una variable no ligada a la derecha del is.En este caso no hay forma trivial de arreglarlo para que el predicado sea totalmente inversible.En este casoimporteCompra(Persona,ImporteTotal):-ImporteTotalisPrecio*1.21,compra(Persona,Planta), precioPlanta(Planta,Precio).ninguna consulta que involucre a esta clusula va a andar porque no hay forma de que la variable Precio est ligada al momento de hacer la cuenta. Arreglar este caso es fcil: ponemos el is al lado del puntoimporteCompra(Persona,ImporteTotal):-compra(Persona,Planta), precioPlanta(Planta,Precio), ImporteTotalisPrecio*1.21.ComparacinSi se compara por mayor, menor, mayor o igual, menor o igual, distinto, lo que comparemos debe estar ligado. P.ej. esta definicinplantaHeavy(Planta):-Nivel&gt;5,nivelVeneno(Planta,Nivel).es incorrecta, porque Nivel no est ligado al momento de comparar. Esta formaplantaHeavy(Planta):-nivelVeneno(Planta,Nivel),Nivel&gt;5.s es correcta.FindallMiremos esta definicin de plantasDerivadasDeplantasDerivadasDe(Planta,ListaPlantasFamiliares):-findall(P2,derivadaDe(Planta,P2),ListaPlantasFamiliares).y supongamos esta consulta?-plantasDerivadasDe(Pl,Plantas).Miremos fijos el findall, recordando que unifica el 3er argumento con la lista de la parte indicada en el 1er argumento de todas las respuestas a la consulta del 2do argumento.En este caso: va a ligar ListaPlantasFamiliares con la lista de los P2 para cada respuesta a la consulta derivaDe(Planta,P2).Como en la consulta no se liga Planta, entonces las respuestas a derivaDe(Planta,P2) van a ser todos los pares de plantas (planta,derivada), y por lo tanto los P2 van a ser todas las plantas derivadas de alguna planta.P.ej. si tenemosderivaDe(p1,p3).derivaDe(p2,p4).derivaDe(p2,p5).ListaPlantasFamiliares va a ser [p2,p4,p5]. Esto nos muestra que con esta definicin el predicado no es inversible para el primer argumento, porque las listas de derivadas de la misma planta son [p3] por un lado, y [p4,p5] por otro; [p2,p4,p5] no puede ser un 2do argumento correcto para este predicado.Para que que el predicado sea totalmente inversible debemos asegurar que la variable Planta entra ligada al findall.plantasDerivadasDe(Planta,ListaPlantasFamiliares):-esPlanta(Planta),findall(P2,derivaDe(Planta,P2),ListaPlantasFamiliares).Miremos ahora qu pasa si definimos el predicado asplantasDerivadasDe(Planta,ListaPlantasFamiliares):- esPlanta(Planta),derivaDe(Planta,P2),findall(P2,derivaDe(Planta,P2),ListaPlantasFamiliares).En este caso, al llegar al findall tanto Planta como P2 ya estn ligadas, entonces la consulta derivaDe(Planta,P2) puede tener a lo sumo una respuesta (positiva, la respuesta no no se cuenta), entonces ListaPlantasFamiliares va a tener a lo sumo un elemento. Vamos a obtener respuestas incorrectas, p.ej.?-plantasDerivadasDe(p2,Lista).Lista=[p4]porque la variable P2, que debe llegar sin ligar al findall, llega ligada.Un ejemplo futbolero ganoContra(argentina, suiza). ganoContra(argentina, belgica). ganoContra(argentina, holanda). ganoContra(belgica, eeuu). ganoContra(holanda, mexico). superEquipo( Equipo ) :- findall(P, ganoContra(Equipo, P), Partidos), length(Partidos, CantGanados), CantGanados &gt; 2.Ahora fijate tirando en prolog la siguiente consulta: superEquipo( X ).ForallEsta definicin del predicado esEspecieComestibleesEspecieComestible(Especie):-forall(especieDe(Planta,Especie),esPlantaComestible(Planta)).no es inversible, porque Especie debe llegar ligado al forall. Si no llega ligada, para que el forall se verifique deben ser comestibles todas las plantas que sean de alguna especie. Esto est explicado en detalle en el artculo sobre forall.Para que sea inversible debemos generar el dominio para la variable EspecieesEspecieComestible(Especie):-esEspecie(Especie),forall(especieDe(Planta,Especie),esPlantaComestible(Planta)).Functores y polimorfismoComo caso particular de los hechos con variables, algo muy comn es tener definiciones como:marca(arroz(Marca),Marca).marca(lacteo(Marca,_),Marca).El predicado marca/2 nos va a resultar muy til para cuando no nos interese qu tipo concreto de producto se est usando, slo que tenga una marca y nos la sepa decir. Lo importante es ser conscientes de que este predicado no es inversible, con lo cual sera incorrecto tratar de usarlo como generador de marcas por ejemplo. Si nos interesa que sea inversible tenemos que usar otro predicado que nos genere los productos, por ejemplo:marca(arroz(Marca),Marca):-precioUnitario(arroz(Marca),_).marca(lacteo(Marca,TipoLacteo),Marca):-precioUnitario(lacteo(Marca,TipoLacteo),_).En resumenResumimos los casos de inversibilidad con un ejemplo de cada unoHechos con variablesleGusta(pepe,_).%LoquelegustadeberaacotarsedealgunaformasisepretendenhacerconsultasexistencialessobrelasegundaaridadNegacinesPlantaComestible(Planta):-not(esVenenosa(Planta)).%PlantadebellegarligadaalnotAritmticaprecioPorCantidad(Planta,Cantidad,PrecioTotal):-precioPlanta(Planta,Precio),PrecioTotalisCantidad*Precio.%CantidaddebellegarligadaalisComparacinplantaHeavy(Planta):-Nivel&gt;5,nivelVeneno(Planta,Nivel).%NiveldebellegarligadaalacomparacinfindallplantasDerivadasDe(Planta,ListaPlantasFamiliares):-findall(P2,derivadaDe(Planta,P2),ListaPlantasFamiliares).``%Plantadebellegarligadaalfindall`forallesEspecieComestible(Especie):-forall(especieDe(Planta,Especie),esPlantaComestible(Planta)).`%Especiedebellegarligadaalforall`Functores y Polimorfismomarca(arroz(Marca),Marca).marca(lacteo(Marca,_),Marca).%Si pretendemos usar marca/2 para hacer consultas existenciales,nopuedetener_nivariablesquenosegenereninternamenteenelencabezado." + +} , + +{ + +"title" : "Paradigma logico como pienso la resolucion de un punto", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---como-pienso-la-resolucion-de-un-punto.html", +"date" : "", +"content" : "Ejemplotour(lokotour,[tramo(madrid,roma), tramo(roma,bonn), tramo(bruselas,burdeos)]).tour(eurobleh,[tramo(madrid,perpignan), tramo(perpignan,paris), tramo(paris,praga)]).pais(bsas,argentina).pais(mendoza,argentina).pais(lima,peru).pais(quito,ecuador).pais(caracas,venezuela).pais(toronto,canada).pais(montreal,canada).pais(madrid,espania).pais(toledo,espania).pais(roma,italia).pais(bonn,alemania).pais(bruselas,belgica).pais(burdeos,francia).pais(perpignan,francia).pais(paris,francia).pais(praga,repcheca).pais(sydney, australia).ciudadGrosa(bsas).ciudadGrosa(lima).ciudadGrosa(quito).ciudadGrosa(caracas).ciudadGrosa(montreal).ciudadGrosa(toledo).Qu no hagoPensar en recorrer, no hay que recorrer nada.Qu s hagoSi tengo que crear un predicado nuevo, pienso en la aridad, y qu representa cada argumento.P.ej. el predicado pasaPorPais relaciona un tour con un pas, entonces es de aridad 2.Pienso en qu condiciones se tienen que dar, y busco la forma (con las herramientas que tengo) de expresarlo en Prolog.Cuando termino, pongo el punto al final de la ltima clusula y ya est, no-hay-nada-ms-que-hacer.P.ej. cundo es cierto que un tour T pasa por un pas P? Cuando la lista de ciudades de T incluye alguna del pas P.Hay muchas veces en que necesito un individuo que no es un argumento del predicado. En ese caso, pienso qu condiciones la relacionan con los individuos que ya tengo (argumentos + los que traje en condiciones anteriores en la misma clusula). Tpicamente, voy a designar estos nuevos individuos con variables, o con cosas ms complejas si me conviene aplicar pattern matching.Veamos algunos ejemplos:Tenemos que hacer el predicado paisInteresante/1, un pas es interesante si tiene al menos dos ciudades grosas.En este caso necesito dos ciudades del pas, las voy a llamar C1 y C2.Qu condiciones tienen que cumplir C1 y C2? Ser del pas, predicado pais/2 que relaciona ciudad con pas (en ese orden!!). El pas lo tengo, es el argumento de paisInteresante Ser grosas, predicado ciudadGrosa/1QuedapaisInteresante(P):-ciudad(C1,P),ciudad(C2,P),ciudadGrosa(C1),ciudadGrosa(C2).Resolvamos pasaPorPais/2 ac necesitamos la lista de ciudades, para eso tenemos el predicado tour/2, la voy a llamar LCiud. la ciudad, a la que voy a llamar C. Qu le tiene que pasar a C? Estar en LCiud (member/2) y ser del pas (pais/2)QuedapasaPorPais(Tour,Pais):-tour(Tour,LCiud),member(C,LCiud),pais(C,Pais)." + +} , + +{ + +"title" : "Paradigma logico conjuncion y disyuncion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---conjuncion-y-disyuncion.html", +"date" : "", +"content" : "Las operaciones lgicas por excelencia son la conjuncin (Y, slo es cierta si ambas condiciones son ciertas) y la disyuncin (O, es cierta si alguna de las condiciones es cierta).Tenemos la siguiente base de conocimiento:madre(nora,luis).madre(nora,ana).madre(lidia,jose).madre(dora,juan).padre(juan,luis).padre(juan,ana).padre(juan,jose).padre(antonio,juan).Supongamos que tenemos que desarrollar en Prolog un predicado hermano/2 que relaciona a dos personas si tienen el mismo padre y la misma madre, y otro llamado hermanastro/2 que relaciona a dos personas si tienen al padre o a la madre en comn (para el ejemplo no se considerar que el O sea excluyente, por ende dos personas hermanas tambin sern hermanastras).La relacin de hermano, dada nuestra base de conocimientos, debera cumplirse para luis y ana, mientras que Jose es slo hermanastro de Luis y Ana. Juan en cambio es hijo nico, con lo cual no debera satisfacer ninguna de las relaciones.Codifiquemos los predicados hermano/2 y hermanastro/2:hermano(Persona,Hermano):-mismoPadre(Persona,Hermano),mismaMadre(Persona,Hermano).hermanastro(Persona,Hermanastro):-mismaMadre(Persona,Hermanastro).hermanastro(Persona,Hermanastro):-mismoPadre(Persona,Hermanastro).mismoPadre(Persona1,Persona2):-padre(Padre,Persona1),padre(Padre,Persona2).mismaMadre(Persona1,Persona2):-madre(Madre,Persona1),madre(Madre,Persona2).La conjuncin en Prolog se logra con la coma, mientras que la disyuncin la conseguimos mediante la definicin de varias clusulas para el mismo predicado. Podemos ver a partir del predicado hermanastro que la bsqueda de soluciones que realiza el motor de Prolog es exhaustiva, ya que si bien jose y luis no cumplen la condicin de tener la misma madre, el resultado a la consulta hermanastro(jose,luis) es verdadero, dado que contina la evaluacin con las otras alternativas para poder satisfacer la relacin.Error comn: Hacer el O antes de tiempoVamos a suponer que tenemos la siguiente lgica una pc es gamer si tiene un disco ssd, un procesador multincleo, y una placa de video shifors 6 o una reidion 8El siguiente cdigo est mal, porque repite lgica:esGamer(PC):- tieneDiscoSSD(PC), tieneMultiNucleo(PC), placa(PC,shifors6). esGamer(PC):- tieneDiscoSSD(PC), tieneMultiNucleo(PC), placa(PC,reidion8). % REPITE LGICA!La definicin de una pc gamer debe ser nica, es decir, tiene que tener una sola clusula. Hay una sola forma de que una pc sea gamer, no dos! Cmo? Nos falta una abstraccin! La abstraccin tienePlacaBuena. Implcitamente esa idea est, pero nos falta en nuestro cdigo. Veamos cmo agregando esa abstraccin evitamos la repeticin de lgica: una pc es gamer si tiene un disco ssd, un procesador multincleo, y una buena placa de videoesGamer(PC):- tieneDiscoSSD(PC), tieneMultiNucleo(PC), tienePlacaBuena(PC). tienePlacaBuena(PC):- placa(PC,shifors6). tienePlacaBuena(PC):- placa(PC,reidion8).% No repite lgica: la definicin de "esGamer" es nica, delega en otro predicado "tienePlacaBuena" los detalles." + +} , + +{ + +"title" : "Paradigma logico detalles del swi prolog", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---detalles-del-swi-prolog.html", +"date" : "", +"content" : "Ojo con los espaciosHay un lugar en donde no puede haber ningn espacio, que es entre el nombre del predicado o functor y el parntesis que abre. O sea, ninguna de las siguientes clusulas compilabueno(X):-not(malo(X)).esTierno(P):-forall(leGusta(P,A),dulce(A)).leGusta(copion,C):-leGusta(pepe,C).leGusta(copion,C):-leGusta(pepe,C).tiene(pepe,libro(octaedro,cortazar)).hay que ponerbueno(X):-not(malo(X)).esTierno(P):-forall(leGusta(P,A),dulce(A)).leGusta(copion,C):-leGusta(pepe,C).tiene(pepe,libro(octaedro,cortazar)).los espacios en otros lados no molestan, p.ej.leGusta(copion,C):-leGusta(pepe,C).tiene(pepe,libro(octaedro,cortazar))." + +} , + +{ + +"title" : "Paradigma logico el forall", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---el-forall.html", +"date" : "", +"content" : "Antes que nadaEl forall es un predicado, o sea, no conviene pensar qu hace, sino qu relaciona, y/o cundo se verifica.El predicado forall conviene pensarlo por lo segundo, o sea cundo se verifica.DefinicinEl forall recibe dos parmetros, los dos deben ser consultas. Las consultas se hacen sobre predicados, o sea que forall es un predicado de orden superior, porque puede manejar predicados dentro de sus parmetros.Hagmosnos la pregunta cundo se verifica?Cuando a todos los que les pasa lo primero, les pasa lo segundo.Dicho un poco ms en tcnico, cuando todas las respuestas de la primer consulta son respuestas de la segunda.Entonces, en las situaciones donde decimos a todos los que blah les pasa bleh es probable que el forall nos venga bien.Un ejemplopartimos de estos hechos dulce(chocolate). dulce(caramelo). dulce(durazno). amargo(radicheta). amargo(cebada). leGusta(roque,chocolate). leGusta(roque,radicheta). leGusta(pepe,cebada). % ... y muchos hechos ms que describen los gustos de un grupo de personas colorDePelo(roque,colorado). colorDePelo(pepe,castanio). % ... etc. con los colores de pelo vive(roque,buenosAires). vive(pepe,mendoza). vive(lucas,salliquelo). % ... y donde vive cada persona de la que queremos hablar ciudadGrande(buenosAires). ciudadGrande(mendoza). % ... y as todas las ciudades grandesy queremos definir esTierno/1, donde decimos que una persona es tierna si todas las cosas que le gustan son dulces.Estamos en un caso candidato a forall: a todas las cosas que le gustan les tiene que pasar ser dulces. En Prolog:esTierno(Persona):-forall(leGusta(Persona, Alimento),dulce(Alimento)). una Persona es tierna si todas las cosas que le gustan son dulces, exactamente lo que dijimos en castellano.Ahora quiero definir el predicado alimentoCurioso/1, un alimento es curioso si solamente le gusta a gente de pelo colorado.Para darme cuenta que el forall me puede servir, lo pienso en trminos de a todos los que les tiene que pasar . A veeer a todas las personas que les gusta el alimento les tiene que pasar ser coloradasQuedaalimentoCurioso(Alimento):-forall(leGusta(Persona, Alimento),esColorado(Persona)).Tener claro lo que se quiere decirEst bien si defino esTierno as?esTierno(Persona):-forall(dulce(Alimento),leGusta(Persona, Alimento)).Claramente no, porque estara pidiendo que le gusten todos los alimentos dulces.Si programar va a consistir en definir condiciones, es relevante entender la diferencia entre todos los alimentos que le gustan son dulces, y le gustan todos los alimentos dulces.El forall en accinSupongamos que hacemos esta consulta:?-esTierno(roque).La variable Persona de esTierno se liga con roque entonces el forall se va a verificar (ver la definicin tcnica) cuando todas las respuestas a la consulta leGusta(roque,Alimento) verifiquen la consulta dulce(Alimento) Para cada respuesta a la consulta leGusta(roque,Alimento), la variable Alimento se va a ligar, en el ejemplo hay dos respuestas, una con chocolate y otra con cebada.La consulta correspondiente ya viene con esa variable ligada, o sea que las consultas que se tienen que verificar para que se verifique el forall sonesDulce(chocolate).esDulce(cebada).Volvamos a la definicin: el forall se verifica si todas las respuestas a la primer consulta son respuestas de la segunda. Mirando el ejemplo de recin debera cerrar el esquema.Qu pasa si no hay soluciones para el primer parmetro de forall?Qu pasa si consultamos si lucas es tierno y en nuestra base de conocimientos no hay nada que le guste??-esTierno(lucas).Esta consulta va a ser cierta, porque si no le gusta nada, es cierto que todas las cosas que le gustan son dulces. Si nos interesa que slo diga verdadero para las personas que les gusta algo, debemos agregar otra condicin fuera del forall que lo asegure.Forall e inversibilidadVeamos qu pasa con las variables y la inversibilidad.Ser inversible el predicado esTierno/1? Hagamos la consulta con una variable en el argumento?-esTierno(X).En este caso la variable Persona llega sin ligar al forall. Entonces la primer consulta esleGusta(Persona, Alimento).Para cada una de las respuestas a esta consulta, se tiene que verificaresDulce(Alimento)donde Alimento es lo que lig la primer consulta.Cules son las respuestas a la primer consulta? Todos los pares (persona,alimento) relacionados por leGusta.Entonces, el forall slo se va a verificar si cualquier cosa que le guste a alguien, no importa a quin, es dulce.Claro, no es lo que queremos. Para lograr lo que queremos, tenemos que lograr que la variable Persona llegue ligada al forall mediante generacin:esTierno(Persona):-persona(Persona),forall(leGusta(Persona, Alimento),esDulce(Alimento)).Una que no falla:fjense que siempre decimos a todos los blah que les pasa la consulta 1, les tiene que pasar la consulta 2.Bueno, para ese blah va a haber una variable, que es Alimento en el caso de esTierno (si todos los alimentos que le gustan ) y P para alimentoCurioso (si todas las personas a quienes les gusta ). Esa variable tiene que llegar al forall sin ligar. El resto de las variables por lo general deben llegar ligadas.Varias condicionesQu pasa si se tienen que cumplir varias condiciones: digamos que un alimento es peculiar si todas las personas a las que le gusta son colorados y porteos nos queda a todas las personas que les gusta el alimento les tiene que pasar ser coloradas y ser porteasentonces la segunda consulta es un y entre dos condiciones.Si pongoesPeculiar(Alimento):-forall(leGusta(Persona, Alimento),colorDePelo(Persona, colorado),vive(Persona,buenosAires)).est mal, porque el forall lleva dos parmetros, no tres. Necesito agrupar colorDePelo() y vive(), para eso los encierro entre parntesis, quedaesPeculiar(Alimento):-forall(leGusta(Persona, Alimento),(colorDePelo(Persona, colorado),vive(Persona, buenosAires))).Pregunto: est bienesPeculiar(Alimento):-forall((leGusta(Persona, Alimento),colorDePelo(Persona, colorado)),vive(Persona, buenosAires)).? No, porque estara pidiendo que todos los colorados a los que les gusta el alimento vivan en Buenos Aires.Para pensarUna que les queda para pensar: ahora tengo que decir que un alimento es marketinable si todas las personas a las que les gusta viven en ciudades grandes. No me interesa que el predicado sea inversible.Tiro tres opciones: elijan la correcta y piensen por qu eligieron esa.esMarketinable(Alimento):-forall(leGusta(Persona, Alimento),vive(Persona, Ciudad),ciudadGrande(Ciudad)). %opcin1esMarketinable(Alimento):-forall((leGusta(Persona, Alimento),vive(Persona, Ciudad)),ciudadGrande(Ciudad)).%opcin2esMarketinable(Alimento):-forall(leGusta(Persona, Alimento),(vive(Persona, Ciudad),ciudadGrande(Ciudad))).%opcin3Ms sobre forallLanse Paradigma Lgico - forall - no siempre con member" + +} , + +{ + +"title" : "Paradigma logico existe vs para todo", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---existe-vs-para-todo.html", +"date" : "", +"content" : "En la lgica de primer orden se trabaja con variables cuantificadas, los cuantificadores indican si algo se cumple para alguno (cuantificador existencial) o para todos (cuantificador universal) los valores de un conjunto de individuos.Lo ms normal es trabajar con el cuantificador existencial, motivo por el cual en el lenguaje Prolog no hay un predicado que la denote, como s sucede para el cuantificador universal.Si queremos definir un predicado estaComplicado/1 que se cumpla para las personas que tienen algn hijo problemtico, podramos hacer:estaComplicado(Persona):-padre(Persona,Hijo),problematico(Hijo).Si luego queremos definir estaHarto/1 de modo que se cumpla para las personas qu slo tiene hijos problemticos, deberamos usar el predicado forall para cuantificar con Para Todo a los hijos de la persona en cuestin:estaHarto(Persona):-padre(Persona,_),%%Generamosalapersonaporquenoquieroqueseaunavariableacuantificar %% porelparatodo,sinounindividuoconcreto. Adems restringe el universo de respuestas %% a personas que tengan al menos un hijo.forall(padre(Persona,Hijo),problematico(Hijo)).Relacin entre Existe y Para TodoExiste una relacin entre el cuantificador universal y el existencial, la misma se establece mediante la negacin.Podramos haber hecho una solucin para estaHarto/1 sin usar forall basndonos en esta equivalencia lgica. Alguien est harto si ninguno de sus hijos no es problemtico.estaHarto(Persona):-padre(Persona,_),not((padre(Persona,Hijo),not(problematico(Hijo))))." + +} , + +{ + +"title" : "Paradigma logico forall no siempre con member", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---forall---no-siempre-con-member.html", +"date" : "", +"content" : "Partimos de la base que el forall corresponde a la idea a todos los que les pasa A, les pasa B.Por alguna razn, una proporcin importante de las personas que estn aprendiendo el paradigma lgico tienden a pensar que cada vez que quiero usar forall, tengo que tener la lista de los que les pasa A, entonces siempre que aparece forall como condicin en una regla, va a ser de esta formaforall(member(E,ListaDeLosQueLePasaA),...condicionesBsobreE...)Tal vez esto est relacionado con asimilar el forall con un for de (ponele) Pascal, que recorre la ListaDeLosQueLePasaA y verifica las condiciones del 2do argumento del forall para cada elemento de la lista.Esta forma de pensarlo no es correcta, veamos dos formas de ver la falla de razonamiento. no conviene pensar en el forall de acuerdo a lo que hace, sino a cundo se verifica, o sea, si pongo forall como condicin de una regla, cuando se va a cumplir. el forall se cumple cuando cada respuesta a su primer argumento (que es una consulta) es respuesta del segundo argumento (que es otra consulta). Entonces, si uso forall poniendo member como primer consulta, lo que estoy diciendo es que todos los elementos de la lista cumplen con la 2da consulta, tiene el mismo resultado de recorrer todos los elementos, pero la idea es otra. Entonces, puedo usar la idea con member, o con cualquier condicin que quiera. Un caso particular en el que se nota este razonamiento inadecuado es cuando se usa un findall seguido de un member, de esta formafindall(X,...condicionesAsobreX...,ListaDeX),forall(member(E,ListaDeX),...condicionesBsobreE...)es ms directo, claro y correcto, usar el forall poniendo directamente a E le pasa A en lugar de E est en la lista de los que les pasa A, en Prolog:forall(...condicionesAsobreX...,...condicionesBsobreE...)Veamos un ejemplo: quiero decir que un tipo es feliz si todos sus amigos son buena onda, tenemos los predicados amigos/2 y esBuenaOnda/1. Si quiero definiresFeliz(Pers)hay una condicin para todos los A pasa B en donde calza justo un forall, A es ser amigo de Pers y B es ser buena onda.Si pienso que forall me sirve solamente para recorrer listas, entonces tengo que armar la lista de los amigos de Pers, y despus fijarme para cada elemento que sea buena onda. En Prolog:esFeliz(Pers):-findall(Amigo,amigos(Pers,Amigo),AmigosDePers),forall(member(Chabon,AmigosDePers),esBuenaOnda(Chabon)).si entiendo que el primer argumento de forall puede ser cualquier consulta, pongo lo que entiendo de la definicin, que es ser amigo de Pers. En PrologesFeliz(Pers):-forall(amigo(Pers,Amigo),esBuenaOnda(Amigo))." + +} , + +{ + +"title" : "Paradigma logico functores", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---functores.html", +"date" : "", +"content" : "Los functores son individos que nos permiten agrupar otros individuos para formar una abstraccin ms compleja. Tienen un nombre y una aridad determinada, si alguno de estos elementos de un functor difiere con otro pasa a ser una abstraccin diferente.Ejemplovende(pepe, tornillo(5,parker)).vende(tony, canilla(redonda,hierro,azul)).Son valores, no predicadosLos functores son valores, individuos.OK, son individuos compuestos, pero siguen siendo individuos. No son predicados, no tienen un valor de verdad.Si bien existe una similitud sintctica entre ellos, la forma de uso es distinta, es por el contexto que Prolog decide si tratarlo como definicin de un hecho, como consulta de un predicado o efectivamente como un functor.No tiene sentido consultar por functores, p.ej. hacer esta consulta?-canilla(X,hierro,Y).sera lo mismo que preguntar?-1.Si hacemos la consulta?-canilla(X,hierro,Y).Y no existe un predicado canilla/3, Prolog va a lanzar un error al intentar ejecutarlo como tal y no encontrar una definicin.Si definimos lo siguiente en nuestra base de conocimientos:vende(pepe,canilla(Forma,Material,Color)).canilla(triangular,hierro,azul).canilla(triangular,porcelana,blanco).Y luego consultamos qu cosas vende pepe, la nica respuesta que puede proveernos es basura con forma de canilla:?-vende(pepe,CosaQueVende).CosaQueVende=canilla(_G9,_G10,_G11).En esas tres lneas de nuestra base de conocimientos tenemos predicado vende/2 que usa un functor canilla/3, y dos hechos para el predicado canilla/3. No hay ninguna relacin entre ellos porque Prolog interpreta a los argumentos de los predicados como individuos. No va a intentar evaluar el functor canilla/3, lo va a tomar como un patrn para unificar en la consulta por pattern matching.Pregunta frecuente: Cmo devolver functores?Antes que nada, el uso de la palabra devolver, marca que faltan entender cosas, porque la pregunta cmo devuelvo no tiene respuesta, no se puede devolver, no existe, es otro paradigma.Si lo comparamos con Pascal, es como si uno preguntara, cmo hago para que sea inversible mi procedimiento?, no tendra sentido, no?.No traten de devolver cosas, sino de establecer relaciones entre ellas.Una forma de arrancar es asumir que el parmetro me viene, entonces yo trato de describir cules son las condiciones que se tienen que cumplir.Una vez llegado a ese punto, si se necesita que sea inversible, analizamos cmo se van ligando las variables y si falta generar los valores posibles en algn caso.Por ejemplo, si pepe vende tornillos parker de todas las medidas disponibles, y sabemos que la medida es un nmero entre 1 y 5 podramos hacer:vende(pepe,tornillo(Medida,parker)):-between(1,5,Medida)." + +} , + +{ + +"title" : "Paradigma logico generacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---generacion.html", +"date" : "", +"content" : "El concepto de generacin puede servir para acotar el conjunto de valores posibles para una variable, pero tambin para ligar la variable con un valor, ya que eso cambia la forma en la que se evalan las siguientes consultas.Esto ltimo tiene que ver con los problemas de inversibilidad, y los casos de uso se dividen en dos grandes grupos:a) Cuando la generacin posibilita la siguiente consulta, por ejemplo:edad(Persona, E), E &gt; 18.Necesito que E tenga un valor para poder evaluar E&gt;18, si no se rompe.Ese sera el caso fcil, si rompe es un claro indicador de que el cdigo no funciona para hacer esa clase de consultas, es fcil de identificar el problema.b) Cuando la semntica de la consulta es distinta a la que quiero, por ejemplo para la siguiente consulta, asumiendo que tenemos en nuestra base de conocimientos un predicado ocupa/3 que relaciona un jugador, un pas y la cantidad de ejrcitos que tiene en ese pas:not((ocupa(Jugador,Pais,CantEjercitos),CantEjercitos&gt;3)) Si la variable Jugador llega ligada y Pais y CantEjercitos llegan libres, podra leerse como: Dado este Jugador, no ocupa ningn pas con ms de 3 ejrcitos. Si Pais tambin llega ligada, la consulta que estamos haciendo sera: No es cierto que este jugador ocupa este pas con ms de 3 ejrcitos. En cambio, si Jugador y Pas estn libres, se debera leer como: No existe ningn jugador que ocupe algn pas con ms de 3 ejrcitos. Entonces, no es que sea obligatorio generar, sino que el significado de la consulta es totalmente distinto, y dependiendo de lo que querramos hacer, hay que ligar previamente el jugador y/o el pas o no.Veamos un ejemplo con el mismo dominio usando findall/3. Si nuestra intencin es definir un predicado cantidadEjercitos/2 que relaciona un jugador con la cantidad total de ejrcitos que tiene en todo el mundo y lo hacemos de la siguiente forma:cantidadEjercitos(Jugador,Cant):-findall(N,ocupa(Jugador,_,N),ListCants),sumlist(ListCants,Cant).Este predicado va a funcionar correctamente (dada una base de conocimientos con muchos jugadores que ocupan varios pases) si la consulta realizada es individual respecto al jugador, pero no es totalmente inversible. Para que lo sea, tenemos que generar al jugador.cantidadEjercitos(Jugador,Cant):-jugador(Jugador),findall(N,ocupa(Jugador,_,N),ListCants),sumlist(ListCants,Cant).De esa forma podremos consultar:?-cantidadEjercitos(Jugador,Cantidad)." + +} , + +{ + +"title" : "Paradigma logico individuos compuestos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---individuos-compuestos.html", +"date" : "", +"content" : "En contraposicin a los tomos y los nmeros, que son individuos simples, existen los individuos compuestos, estos son: los functores las listasPara acceder a los componentes de un individuo compuesto podemos usar Pattern Matching.En el caso de los functores, los componentes son los argumentos del functor. Si los quiero por separado, p.ej. si tenemos un functor de la forma canilla(Forma,Material,Color) y tenemos un predicado vende/2 que relaciona un local con una cosa que vende:vende(pepe,canilla(triangular,hierro,azul)).podemos armar este predicadohayMaterial(Local,Mat):-vende(Local,canilla(_,Mat,_)).en donde estamos abriendo el functor canilla/3 mediante pattern matching y as unificando la variable Mat con el material de la canilla que se vende en el local.En el caso de las listas hay dos patrones bsicos, una lista puede ser la lista vaca o con almenos un elemento. En caso de no ser la lista vaca los componentes son cabeza y cola, y la notacin es[Cabeza|Cola]como la cola tambin es una lista, si la lista con la que quiero matchear espero que tenga al menos dos elementos puedo hacer:[Elem1|[Elem2|Resto]]Probar p.ej. con esta consulta?-[Elem1|[Elem2|Resto]]=[a,e,i,o,u].Alternativamente se puede usar el patrn [Elem1, Elem2 | Resto] con el mismo objetivo, es un azcar sintctico para unificar dos variables con los primeros dos elementos de la lista.El caso tpico para usar Pattern Matching sobre listas es en la recursividad.Combinando constructores de individuos compuestosSe pueden combinar estas dos formas de armar individuos compuestos, p.ej. con esta lista de functores.recorrido(linea19,[estacionTren(once),avenida(rivadavia),calle(salguero),calle(guardiaVieja),facultad(utnMedrano),calle(forest),estacionTren(chacarita)]).si quiero saber por qu estaciones de tren pasa una lnea de colectivos, puedo definirlo aspasaPorEstacion(Linea,Estacion):-recorrido(Linea,Recorrido),member(estacionTren(Estacion),Recorrido).si consulto?-pasaPorEstacion(linea19,Est).voy a obtener como respuestasEst=once;Est=chacarita;No" + +} , + +{ + +"title" : "Paradigma logico individuos simples", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---individuos-simples.html", +"date" : "", +"content" : "Los primeros individuos con los cuales estaremos trabajando son los denominados simples (en contraposicin a los individuos compuestos). Los que nos van a interesar para trabajar en general son los tomos y los nmeros.tomosLos tomos son valores que representan a una entidad indivisible. En el siguiente ejemplo podemos ver cmo se usan tomos para modelar la informacin:padre(homero,bart).padre(homero,lisa).padre(homero,maggie).padre(abe,homero).Los tomos que se usan en el ejemplo son homero, bart, lisa, maggie y abe. Siempre que aparezca el tomo homero en mi programa me voy a estar refiriendo a la misma persona. Por eso puedo definir hermano/2 como:hermano(H1,H2):- padre(Padre,H1), padre(Padre,H2), H1&#92;=H2.Si los dos individuos que queremos relacionar con el predicado hermano/2 tienen al mismo padre, la relacin se va a cumplir (usamos el &#92;= para asegurarnos que una respuesta posible no sea H1=bart, H2=bart).Es importante notar que estos individuos no son strings?-length("homero",X).X=6?-length(homero,X).No&lt;--porprincipio de universo cerradoNmerosLos nmeros pueden usarse para lo mismo que en cualquier otro paradigma. Los podemos comparar, saber si uno es mayor que otro y usarlos para resolver operaciones aritmticas. Pero siendo que estamos en lgico y contamos con la idea de inversibilidad y mltiples respuestas tambin podemos hacer cosas como:?-between(3,7,X).X=3;X=4;X=5;X=6;X=7;NoAlgunas consideraciones que hay que tener con los operadores como el &#92;=, el &gt;, el + etc.. es que requieren que las variables utilizadas ya se encuentren ligadas. De lo contrario ocurrir un error en tiempo de ejecucin como este:?-3&gt;A.ERROR:ArgumentsarenotsufficientlyinstantiatedDe la misma forma, el between que vimos recin slo es inversible para el tercer argumento, los dos primeros que definen el rango deben ser valores concretos. Esto tiene sentido ya que las posibles respuestas seran infinitas si no se define un mximo y un mnimo." + +} , + +{ + +"title" : "Paradigma logico introduccion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---introduccion.html", +"date" : "", +"content" : "El paradigma lgico se basa en la definicin de reglas lgicas y es un paradigma declarativo as que si no lo leste todava te recomiendo leer antes sobre Declaratividad. En este artculo hablamos principalmente de la teora del paradigma lgico, pero para los ejemplos tomamos como base el lenguaje PrologIntroduccin: SilogismosCmo describir un problema usando la lgica? Qu tipo de problema podemos describir?Comencemos con un ejemplo simple, seguramente muchos de ustedes lo habrn escuchado alguna vez:Scrates es hombreTodos los hombres son mortalesLuego qu podemos deducir de esto? Claro adivinaste, que Scrates es mortal. De eso se trata la programacin lgica, vamos a describir nuestro conocimiento en formas de reglas y vamos a permitir que otra cosa (el motor) se ocupe de procesar ese conocimiento y sacar conclusiones al respecto.Y solito se da cuenta de las cosas? Ms o menos, en realidad no podemos pedirle al motor que solamente se ponga a deducir y que nos diga a qu conclusin llega, hay que hacerle preguntas ms concretas. Por ejemplo podemos preguntarle: si socrates es mortal, y nos va a decir que s qu mortales conoce, y nos va a decir que socrates es mortalEsos son los dos tipos de preguntas bsicas que el motor va a saber contestar, despus vamos a bajar en detalle sobre esto.Cmo lo bajamos a cdigo?Programemos este mismo ejemplo en Prolog, en realidad es bastante simple:hombre(socrates).mortal(X):- hombre(X).Qu quiere decir esto? hombre(socrates) afirma que Scrates es un hombre, o dicho de otra manera que socrates tiene la caracterstica hombre. Es una afirmacin que afecta nicamente a Scrates y la llamamos un hecho, ya que es una declaracin que no depende de nada para ser verdadera. mortal(X):-hombre(X) es lo que llamamos una regla y se puede leer como: X es hombre X es mortal. La regla es una implicacin, el antecedente es hombre(X) y el consecuente es mortal(X). Esto quiere decir que para todo X que tenga la caracterstica hombre se da que ese X tambin tiene la caracterstica mortal (o ms corto: todos los hombres son mortales).Fijate que socrates est en minscula, mientras que la X aparece en mayscula, por qu? Los trminos en minscula se refieren a cosas particulares y las palabras en mayscula son incgnitas (o variables).Eso se relaciona tambin con que la primera lnea sea un hecho (porque habla de un individuo particular) y la segunda sea una regla (porque habla de todos los hombres).Pero la principal diferencia entre el hecho y la regla es que la regla tiene un antecedente (que se debe cumplir para que se cumpla la regla) y el hecho no, el hecho es verdadero siempre. En programas ms complejos, a veces pasa que tenemos hechos que usan variables o reglas sobre individuos particulares.Los hechos me permiten definir por extensin el conjunto de individuos que tienen una caracterstica. Las reglas me permiten hacer esa misma definicin por comprensin.Un poco de teoraSi entendiste todo hasta ac, es momento de formalizar algunas cositas acerca del programa que hicimos. Antes que nada: La base de conocimiento se compone de clusulas que definen predicados partiendo de los individuos de los que queremos hablar (para ms detalles sobre estos trminos, podemos pasar a ver algunas definiciones). Un programa Prolog es una base de conocimiento.Para obtener resultados a partir de un programa, hacemos consultas individuales y existenciales.Universo CerradoQu pasa si ahora quiero preguntar si Aristteles es mortal??- mortal(aristoteles).Al ejecutar esa consulta, la secuencia de pasos del motor (simplificada) es la siguiente: El motor buscar en la base de conocimientos las diferentes clusulas del predicado mortal/1, en particular las que matcheen con mortal(aristoteles). Al hacer esto encontrar una nica regla: mortal(X):-hombre(X). Ergo, para probar que Aristteles es mortal, deber probar que es hombre. Al intentar verificar si aristoteles es un hombre, es decir la consulta hombre(aristoteles). Pero la nica definicin del predicado hombre es hombre(socrates), que no matchea con hombre(aristoteles). La base de conocimientos no dice nada acerca de aristteles, por lo tanto no se puede verificar que Aristteles sea mortal.En este momento aparece un concepto que llamamos principio de universo cerrado, que dice que el motor asume como falso todo lo que no pueda probar como verdadero, es decir que si al preguntarle si aristoteles es mortal, me va a contestar que no!Muchos entornos (tanto dentro del paradigma lgico como en otros muchos lugares) trabajan con este principio. Aunque no es la nica forma de trabajar, es algo bastante frecuente dado que lo contrario es en general ms complicado de implementar y de utilizar.Cmo solucionar el problema?Agregando el hecho que indica que Aristteles es un hombre:hombre(aristoteles).Si volvemos a hacer la misma consulta ahora vamos a tener el resultado esperado." + +} , + +{ + +"title" : "Paradigma logico inversibilidad", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---inversibilidad.html", +"date" : "", +"content" : "DefinicinLa inversibilidad es una de las caractersticas distintivas del paradigma lgico, que no aparece en los paradigmas funcional ni objetos. Que un predicado sea inversible significa que los argumentos del mismo pueden usarse tanto de entrada como de salida. Es decir, no necesits pasar el parmetro resuelto (un individuo concreto), sino que pods pasar una incgnita (variable sin unificar).Imaginate un predicado esNatural/1 que te dice si un nmero es natural:esNatural(1)YesesNatural(-2)NoCuando un predicado es inversible, tambin pods hacer otro tipo de consultas, poniendo una incgnita en el parmetro en lugar de un valor:esNatural(N)N=1;N=2;N=3;etc...Esta caracterstica es exclusiva del paradigma lgico, ya que est basado en el concepto de relacin matemtica (y no en el de funcin, donde siempre bamos de un dominio a una imagen).La inversibilidad no tiene que ver solamente con que d error si pasamos una incgnita donde no podamos hacerlo, muchas veces lo que pasa es que -sin dar error- se comporta incorrectamente o de forma distinta a la que uno esperara. En ese caso tambin decimos que no es inversible.EjemplosVeamos este programavive(ruben,lanus).vive(ana,lanus).vive(laura,boedo).vive(susi,bernal).sonVecinos(P1,P2):- vive(P1,B), vive(P2,B), P1&#92;=P2.esDelSur(P):-vive(P,lanus).esDelSur(P):-vive(P,bernal).Todos los predicados que aparecen son totalmente inversibles, porque puedo hacer consultas con cualquier combinacin de valores e incgnitas. Qu quiere decir esto? Mir todas las consultas que se pueden hacer?-vive(ruben,B).?-vive(P,lanus).?-vive(ruben,boedo).%respondequeno?-vive(P,B).y lo mismo para sonVecinos?-sonVecinos(ruben,X).?-sonVecinos(X,ruben).?-sonVecinos(ana,ruben).%respondeques?-sonVecinos(X,Y).para esDelSur/1 hay menos combinaciones, porque tiene un slo argumento?-esDelSur(susi).%quteparecequeresponde??-esDelSur(P).%idemObservar que cada predicado tiene una definicin sola, no tengo que pensar en distintas definiciones para cubrir las distintas combinaciones entre valores e incgnitas. Para sonVecinos/2, no tengo que armar una regla por si me consultan con dos valores, una distinta por si me consultan con dos incgnitas, etc..OJO - inversible no es lo mismo que simtricoSigamos con el programa anterior. Ya vimos que los tres predicados son inversibles.Ahora bien, son simtricos?Empecemos pensando qu quiere decir simtricos. Es como una relacin simtrica de las de teora de conjuntos: una relacin R es simtrica si siempre que pasa aRb, tambin pasa bRa.Entonces, el predicado vive/2, es simtrico? Veamos. Si consulto?-vive(ruben,lanus).responde que s, o sea, ruben / vive / lanus. En el esquema aRb, es a: ruben R: vive b: lanusO sea que bRa sera?-vive(lanus,ruben).y la respuesta de esto claramente va a ser no.Entonces el predicado vive/2 no es simtrico. Pero ya vimos que s es inversible, porque inversible quiere decir puedo hacer consultas con cualquier combinacin de valores e incgnitas. y no quiere decir si invierto los argumentos da las mismas respuestas. Esto es simetra.En cambio, sonVecinos/2 es esperable que se verifique para el mismo par de individuos en cualquier orden. A su vez, por como est definido es inversible, pero no tiene nada que ver una cosa con la otra.Observar que la nocin de simetra slo se aplica a predicados de 2 argumentos (para esDelSur/1 cmo sera ser simtrico? No tiene sentido), mientras que la de inversibilidad se aplica a cualquier predicado.Resumen ejecutivo: ojo al piojo, inversibilidad es una cosa muy distinta a simetra, no confundirse. Si no queda claro, consulte con su docente amigo. Lo que nos va a interesar en la materia es el concepto de inversibilidad.Cmo hacs que un predicado sea inversible?En principio, todo predicado es inversible salvo que caiga en un caso de no-inversibilidad.Estos casos tienen que ver con las submetas de un predicado que requieren variables ligadas, en estas cosas es que hay que fijarse para saber qu hace falta generar.Por ejemplo: cuando una de las componentes de un predicado es un not/1 , necesits que el predicado que le mands tenga sus parmetros unificados. Cuando uss una evaluacin matemtica (ej: X is N &#92;* 2), necesits que lo de la derecha (la N) est unificado.Cul sera el uso?Inherentemente es ms potente que una funcin, ya que te permite encontrar todos los valores para los cuales una relacin se cumple (y esto tiene que ver tambin con la idea de mltiples resultados).La ventaja inmediata es que te permite ms formas de usarlo, lo tpico: puedo preguntar si un alumno aprob, o todos los alumnos que aprobaron, etc.Luego podra aparecer otra ventaja y es que si todos mis predicados son inversibles, eso de verdad me permite usarlos sin pensar nada nada nada en la secuencia y me da ms lugar a slo declarar el conocimiento. Y eso le da una potencia ms grande a mi lenguaje/paradigma/entorno de programacin.(Igual no debe entenderse de lo ltimo que todos los predicados que hago deben ser inversibles. )" + +} , + +{ + +"title" : "Paradigma logico listas", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---listas.html", +"date" : "", +"content" : "MotivacinSi nuestra base de conocimiento espadre(homero,bart).padre(homero,maggie).padre(homero,lisa).Vimos varias consultas posibles%Esciertoquehomeroespadredebart??-padre(homero,bart).Yes%Esciertoquehomeroespap??-padre(homero,_).Yes%Quienessonlospadresdebart??-padre(P,bart).P=homero%Quienessonloshijosdehomero??-padre(homero,H).H=bart;...%Quienessonpadreehijo??-padre(X,Y).X=homeroY=bart;etc.Pero a pesar de esta gran gama de consultas hay ciertas preguntas que se vuelven complicadas o imposibles. Vamos a tomar como ejemplo la siguiente pregunta: Cuntos hijos tiene homero?.En el estado actual de las cosas tenemos que hacer la consulta?-padre(homero,H).H=bart;H=lisa;H=maggie;NoContamos la cantidad de respuestas, en este caso los posibles valores de H y obtenemos la respuesta 3. Ahora bien, esto es impracticable cuando el nmero de respuestas es alto y adems no responde a nuestra pregunta de forma directa.Pensemos en predicados e individuos y definamos un predicado que relacione lo que nos interesa una persona y su cantidad de hijos. Dicho predicado puede llamarse cantidadDeHijos/2.?-cantidadDeHijos(homero,C).C=3Perfecto, ya tenemos definido nuestro objetivo ahora definamos el predicado a travs de una regla (lo quiero hacer por comprensin porque quiero que me sirva para cualquier persona, no solo homero)cantidadDeHijos(P,Cantidad):-....Para resolver esto volvamos un poco para atrs. En el mundo del paradigma lgico qu es lo que da 3? La cantidad de respuestas de la consulta .Entonces lo que nos gustara hacer es tener en un solo lugar todas las respuestas a la consulta para despus contar todos los posibles valores de H pero todava no sabemos cmo hacer eso as que imaginemos que por el momento es magia.El conjunto como un individuoSin importar como obtenemos esas respuestas las queremos tener identificadas en un solo lugar, en un solo individuo un individuo compuesto que representa un conjunto!En el caso de homero ese conjunto va a ser .A este tipo de individuo que representa conjuntos lo vamos a llamar lista y se encierra entre corchetes () donde cada elemento del conjunto se separa por coma ().En nuestra definicin del predicado vamos a definir una variable Hijos que va representar a dicho conjunto, pero a nosotros no nos interesa el conjunto de hijos sino la cantidad de elementos que tiene ese conjunto Una vez hecha la magia, lo que necesitamos es un predicado que relacione a un conjunto con su cantidad de elementos y eso ya viene con prolog. Ese predicado se llama .cantidadDeHijos(P,Cantidad):-acvalamagiaqueledavaloralavariableHijos,length(Hijos,Cantidad).Nos falta hacer la magia!Cmo obtener todas las respuestas juntas?Si tenemos una forma de obtener mltiples respuestas a una consulta (en este caso, todos los H que son respuesta de la consulta padre(P,H) cuando P es por ejemplo homero), y lo que queremos es que todas esas respuestas estn juntas en una lista, hay un predicado en Prolog que hace exactamente eso:findall(UnIndividuo,Consulta,Conjunto)Donde: normalmente es una variable que se usa en la Consulta es una lista con todos los individuos que se encontraron al consultar la Consulta Entonces:findall es un predicado que relaciona a una consulta con el conjunto (lista) de sus respuestas.El otro parmetro me permite indicar qu es lo que me interesa para completar la lista. Volviendo a nuestro ejemplocantidadDeHijos(P,Cantidad):-findall(H,padre(P,H),Hijos),length(Hijos,Cantidad).Con esta definicin nuestro objetivo se cumple?-cantidadDeHijos(homero,C).C=3Observamos que la variable de la clusula que define cantidadDeHijos llega ligada al findall, por lo tanto la consulta que est adentro (el 2do parmetro) queda que efectivamente tiene 3 respuestas.Inversibilidad del predicado findallAhora bien, agregemos algunos hechos a la base de conocimientopadre(homero,bart).padre(homero,maggie).padre(homero,lisa).padre(abraham,homero).padre(abraham,herbert).Y pensemos en otra consulta?-cantidadDeHijos(P,C).C=5.No funciona como esperbamos, a qu se debe?Debemos mirar la consulta que se est realizando en el findall (el 2do parmetro): . Si pensamos cuntas respuestas tiene esa pregunta veremos que efectivamente son 5!%Quienessonpadreehijo??-padre(P,H).P=homero,H=bart;P=homero,H=maggie;P=homero,H=lisa;P=abraham,H=homero;P=abraham,H=herbert.En el findall/3 como primer parmetro dijimos que nos interesa solamente la variable H de cada respuesta, e Hijos ser un conjunto de esos H. Por lo tanto Hijos es la lista [bart,maggie,lisa,homero,herbert] que tiene 5 elementos (la respuesta a nuestra consulta).Un findall totalmente inversible: GeneracinEl problema est en la consulta de adentro del findall, no queremos preguntar Quienes son padre e hijo? sino Quienes son hijos de P? (risas) y para preguntar eso P debe llegar ligada al findall, para poder preguntar por los hijos de una persona en particular.Ahora tenemos que averiguar cmo ligar a P, y para eso hay que pensar cules seran los posibles P que nos interesan. Una respuesta sencilla es pensar que queremos que P sea una persona, entonces podramos agregar al antecedente la restriccin: .(Tambin se podra usar el predicado padre/2 en lugar de persona/1, analizamos la diferencia entre ambos en el prximo apartado.)cantidadDeHijos(P,Cantidad):-persona(P),%Generacion,asilavariablePllegaligadaalfindallfindall(H,padre(P,H),Hijos),length(Hijos,Cantidad).Lo que logramos al hacer que P llegue ligada al findall es que el predicado cantidadDeHijos/2 sea totalmente inversible. A esta tcnica la denominamos generacin.Dos formas distintas de generacinDijimos que en realidad hay dos formas de determinar cules son todos los P que me interesan: Una forma es decir que P es una persona, entonces podramos poner: Por el otro podemos pensar que P tiene que ser padre, entonces surge la opcin: . (Me interesa que sea padre y no me importa en principio cules son sus hijos.Qu pasara si usamos en lugar de como generador?cantidadDeHijos(P,Cantidad):-padre(P,_),%Generacion,asilavariablePllegaligadaalfindallfindall(H,padre(P,H),Hijos),length(Hijos,Cantidad).La diferencia la vamos a encontrar si hacemos la consulta:?-cantidadDeHijos(bart,C).Con la solucin propuesta en el apartado anterior nos dice que bart tiene cero hijos:?-cantidadDeHijos(bart,C).C=0Con la segunda posibilidad, bart no es una posible respuesta para (porque no es padre de nadie). Entonces lo que voy a obtener es:?-cantidadDeHijos(bart,C).NoEn este caso consideramos que es ms saludable un 0 que un No. Independientemente de eso, lo que debe quedar de todo esto es que las distintas formas de generar nos pueden dar diferentes resultados como respuesta y hay que elegir qu queremos.Una pregunta adicional que podra surgir es: qu pasa si no tenemos el predicado persona? Bueno, habr que agregarlo a la base de conocimientos, y para ello tenemos dos posibilidades:Por extensin:uno por uno enumerando cada persona (un hecho para cada persona:persona(bart).persona(lisa)....etc.Por comprensin:con una regla descubrir quines podemos considerar persona a partir de la informacin que ya tenemos. Una forma de hacer eso sera:persona(Papa):-padre(Papa,_).persona(Hijo):-padre(_,Hijo).Es decir, el que es padre de alguien es una persona, y el que es hijo tambin.Haciendo consultas ms heaviesEn el segundo parmetro del findall se pueden poner cualquier tipo de consulta, no es necesario que solo 1 predicado est involucrado.findall(X,(p(X),q(X),r(X),,s(X)), Xs)Hay que encerrarla entre parntesis para no cambiar la aridad de findall que es tres (3).EjemploSi queremos hacer un predicado que me diga cuantos hijos pibes tiene una persona podemos hacer estoLos X que me interesan son los que cumplen la consulta (padre(P,H),esPibe(H))cuantosPibes(Persona,Cant):-persona(Persona),findall(H,(padre(Persona,H),esPibe(H)),Pibes),length(Pibes,Cant).Otro ejemplo usando listasinterseccion(Xs,Ys,Zs):-findall(E,(member(E,Xs),member(E,Ys)),Zs).Usando individuos compuestos en el primer parmetro del findallEn ciertas situaciones nos interesa tener una lista de individuos que hasta el momento no existan en nuestro programa o que no estn presentes explcitamente en la consulta (o sea, en el 2do parmetro del findall).Ejemplo:Imagnense que tenemos un programa en donde se define el predicado puntaje/2 que relaciona a un equipo con la cantidad de puntos que tiene. Un requerimiento bastante usual en un programa de este estilo, es conocer la tabla de posiciones que se puede ver como un conjunto de individuos o sea una lista en donde cada individuo que la compone es un equipo con su cantidad de puntos.?-findall(????,puntaje(Equipo,Cant),Tabla).La pregunta a responder es qu ponemos en ????. Necesitamos definir un individuo que est compuesto por otros 2 individuos (Equipo y Cant). Para hacer esto nada mejor que un functor (un indivudo compuesto de tamao fijo), le inventamos un nombre por ejemplo ptos?-findall(ptos(Equipo,Cant),puntaje(Equipo,Cant),Tabla)Recuerden: ptos es un functor no un predicado puntaje es un predicado no un functor Tabla es una lista de functores ptos que verifican la consulta que est como segundo parmetro del findallSacando los repetidos con distinct Ver DistinctRecursividad Con Listas Ver Recursividad en LogicoErrores comunesfindall y memberEl error ms comn para quienes no estn acostumbrados a pensar en trminos del paradigma es armar listas cuando no son necesarias para la resolucin del problema. Esto se pone en evidencia por el uso del findall seguido por un member sobre la lista resultante. El findall arma listas, el member las desarma son operaciones inversas!Por ejemplo, si quiero saber quines son los hijos de homero puedo consultar padre(homero,Hijo). Resolver esto como:?-findall(H,padre(homero,H),Hijos),member(Hijo,Hijos).es no estar entendiendo la forma de pensar.Si bien este primer ejemplo puede parecer obvio, hay casos en los cuales no es tan evidente, por ejemplo cuando se arma una lista de los que cumplen CONDICION con el predicado A y el predicado B consulta A y luego se obtienen los elementos con member.Siguiendo el ejemplo anterior de los hijos pibes, podemos mostrar el problema anterior de esta forma:hijosPibes(P,Pibes):-persona(P),findall(H,(padre(P,H),esPibe(H)),Pibes).esHijoPibe(Persona,Hijo):-hijosPibes(Persona,Pibes),member(Hijo,Pibes).En ese caso todo lo que necesitbamos era consultar por existencia quin cumple CONDICION, y si todava nos interesa hijosPibes/2 podramos hacer los siguientes cambios:hijosPibes(P,Pibes):-persona(P),findall(Hijo,esHijoPibe(P,Hijo),Pibes).esHijoPibe(Persona,Hijo):-padre(Persona,H),esPibe(H).En este caso fue simple porque B modelaba directamente CONDICION, pero bien podra pasar que nos est faltando una abstraccin para modelar CONDICION, que podemos solucionar definiendo otro predicado C y modificando los predicados A y B para que usen C.findall y lengthUno de los usos ms comunes de findall tiene como objetivo saber cuntos individuos cumplen una determinada condicion, como en el ejemplo visto anteriormente de cantidadDeHijos/3. Sin embargo hay casos en los cuales pensamos la solucin a un problema bsico en trmino de cantidad de respuestas, lo cual disminuye la declaratividad de la solucin. Veamos un par de ejemplos:esPadre(Persona):-persona(Persona),findall(Hijo,padre(Persona,Hijo),Hijos),length(Hijos,CantidadDeHijos),CantidadDeHijos&gt;=1.noTieneHijos(Persona):-persona(Persona),findall(Hijo,padre(Persona,Hijo),Hijos),length(Hijos,0).Estos dos predicados podran definirse sin uso de listas, y no slo eso sino que la solucin de ambos es mucho ms sencilla. En ambos casos debera simplemente trabajar con la idea de existencia, ya sea afirmndola o negndola, o sea:esPadre(Persona):-padre(Persona,_).noTieneHijos(Persona):-persona(Persona),not(padre(Persona,_)).Caso existe ms de unUn problema comn es saber si hay ms de un individuo que cumple una condicin. Si alguien tiene ms de un hijo, por ejemplo. Eso lo podemos saber as:tieneMasDeUnHijo(Persona):-persona(Persona),findall(Hijo,padre(Persona,Hijo),Hijos),length(Hijos,CantidadDeHijos),CantidadDeHijos&gt;1.Hay un problema nuevamente con la declaratividad, y con la manera de pensar lgicamente. Si le damos una vuelta de tuerca, podemos resolver este ejercicio sin necesidad de armar una lista y contar.Esto se logra pensando as: tengo ms de un hijo si existen dos hijos diferentes.tieneMasDeUnHijo(Persona):-padre(Persona,Hijo1),padre(Persona,Hijo2),Hijo1&#92;=Hijo2.Es mucho ms directo! Y respeta mejor las ideas del paradigma.Caso existe slo unEste es para pensar:tieneSoloUnHijo(Persona):-persona(Persona),findall(Hijo,padre(Persona,Hijo),Hijos),length(Hijos,1).No podra hacerlo de otra forma?Alguien tiene un slo hijo si: Existe al menos un hijo, y No existe ms de un hijo(sale usando lo explicado arriba)findall y forallY otro caso tpico de mal uso de findall y member aparece al tratar de usar el forall." + +} , + +{ + +"title" : "Paradigma logico multiples respuestas", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---multiples-respuestas.html", +"date" : "", +"content" : "Al hacer una consulta existencial se puede obtener ms de una respuesta. Esto se debe a que estamos trabajando con relaciones, no con funciones. Las funciones son un caso particular de relacin que se caracterizan por cumplir con unicidad (para cada valor de entrada hay una nica salida), mientras que las relaciones no tienen esa restriccin.P.ej. si Pedro tiene como primos a Luca, Alan y Guido; entonces la relacin ser primos relaciona a Pedro con tres personas distintas:primo(pedro,lucia).primo(pedro,alan).primo(pedro,guido).Entonces si consulto quin es un posible primo de Pedro, lo que debe pasar es que se obtengan tres respuestas independientes entre ellas: una respuesta por cada primo que tenga Pedro.?-primo(pedro,Primo).Primo=lucia;Primo=alan;Primo=guidoEn funcional no tendra sentido que para la funcin primo existan 3 respuestas para el valor Pedro, dado que no cumplira con la propiedad de unicidad de las funciones. La nica forma de responder que tanto Luca, Alan y Guido son primos de Pedro es mediante el uso de valores compuestos para representar al conjunto que incluye a todos ellos.Ahora, si quisiramos resolver un problema donde esperamos que cada individuo se relacione con un nico valor, eso debe asegurarse dentro de la lgica del predicado.Pongamos un ejemplo sencillo para analizar: supongamos que queremos definir un predicado que relacione a un valor consigo mismo, salvo que ese valor sea el 0, en cuyo caso se lo debe relacionar con el nmero 1. No alcanzara slo con explicitar mediante un hecho que el 0 se relaciona con el 1 y luego generalizar lo que pasa con los otros valores de esta forma de esta forma:p(0, 1).p(X, X).Ya que si consultamos:?- p(0, Valor).Valor = 1;Valor = 0Para que la nica respuesta posible sea 1, tenemos que asegurar que el caso general excluya al 0, lo cual puede lograrse de la siguiente forma:p(0, 1).p(X, X) := X &#92;= 0." + +} , + +{ + +"title" : "Paradigma logico negacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---negacion.html", +"date" : "", +"content" : "El predicado de orden superior ms simple, y a la vez muy utilizado, es el not/1, que representa una negacin. Si P es una proposicin, entonces not(P) es una proposicin que niega el valor de verdad asumido para P. As, la negacin de algo falso se toma por verdadera, y la negacin de algo con valor cierto, se toma como falso.EjemplosConsultas IndividualesSupongamos lo siguiente:esMalo(feinmann).esMalo(hadad).esMalo(echecopar).Y miremos los resultados de las siguientes consultas:?-esMalo(hadad).true?-not(esMalo(hadad)).false?-esMalo(bambi).false?-not(esMalo(bambi)).trueAhora, miremos sto:?-esMalo(34).falseClaro que no es malo! El 34 no lastimara una mosca! Porque ste paradigma se basa en el concepto de Universo Cerrado. (Si no est en la base, es falso). Entonces, la siguiente consulta da verdadero:?-not(esMalo(34)).trueConsultas Existenciales VariablesRecordemos cul es el significado de la siguiente consulta:?-esMalo(_).As, con la variable annima, estoy preguntando si existe un malo. Bueno, eso es cierto:?-esMalo(_).trueAhora bien, veamos qu sucede si preguntamos si es cierto que no existe un malo?-not(esMalo(_)).falsePor ltimo, se podr usar una variable que no sea la variable annima dentro de una negacin?Para responder a eso vamos a tener que hablar sobre inversibilidad.InversibilidadAgreguemos lo siguiente al ejemplo:esPersona(feinmann).esPersona(hadad).esPersona(echecopar).esPersona(bambi).esPersona(fer).esPersona(lucas).esBueno(Persona):- not(esMalo(Persona)).ProblemaVeamos el resultado de la siguiente consulta:?-esBueno(lucas).true.?-esBueno(fer).true.Y ahora tratemos de preguntar si existe algn bueno (claro que existen!):?-esBueno(X).false.Qu pas?? No debera ser capaz de decirnos quines son buenos?InterpretacinMi regla dice que se cumple esBueno(X), si se cumple not(esMalo(Persona)).Sabiendo que la variable annima es igual que cualquier otra variable, slo que la usamos cuando no nos interesa conocer qu individuo hace que se cumpla la consulta, stas dos consultas tienen el mismo valor de verdad, que para nuestra base de conocimientos sera verdadero ya que existe alguien que es malo:?-esMalo(_).?-esMalo(X).Entonces, la siguiente consulta (equivalente a esBueno(X)) dar falso:?-not(esMalo(X)).false.Porque estoy preguntando si es cierto que no existe alguien malo.Normalmente si usamos una variable no annima, Prolog tratar de darnos ejemplos que hacen verdadera esa consulta. Pero en el caso de la negacin, es imposible para el motor encontrar ejemplos de individuos que satisfagan la consulta, porque son infinitos! Por ejemplo, el 34 no es malo?-esBueno(34).true.SolucinEntonces Qu hacemos?Generamos.Generar es agregar una condicin que s sea inversible antes del not, para que las variables lleguen ligadas al mismo. De sta manera, transformamos la consulta dentro del not que poda llegar a ser una consulta existencial en una consulta individual, que funcionan como nosotros esperamos (Leer ms ariba).esBueno(Persona):- esPersona(Persona), not(esMalo(Persona)).Y as podemos consultar si existe un bueno, y tener tambin ejemplos de buenos.?-esBueno(X).X=bambi;X=fer;X=lucas.Para ms informacin sobre inversibilidad y generacin, visitar el artculo Paradigma Lgico - inversibilidadAdems, nuestro nuevo predicado esBueno se va a comportar distinto que antes ante esta consulta individual:?-esBueno(34).false.Si bien el nmero 34 nos gusta mucho, sera conceptualmente incorrecto aceptar que fuera bueno, ya que nuestro dominio trabaja con personas, y es sobre ellas que, en ste caso, queremos verificar la propiedad de ser buenas. Con el agregado que hicimos no slo resolvimos el problema de las consultas existenciales, sino que adems sirvi para acotar el dominio de aquellos que pueden ser buenos." + +} , + +{ + +"title" : "Paradigma logico un poco de nomenclatura", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico---un-poco-de-nomenclatura.html", +"date" : "", +"content" : "Cuando describimos los elementos de un programa en lgico (ya sea para su definicin como su uso) vamos a usar los siguientes trminos: Individuo Individuo simple tomo Nmero Individuo compuesto Lista Functor Predicado Propiedad Relacin Clusula Hecho Regla Consulta Individual Existencial A continuacin mostramos un programa sencillo (la base de conocimiento) como para tener de referencia e identificar cundo usamos cada uno de estos trminos.hombre(socrates).hombre(solon).hombre(pericles).hombre(arquimedes).mortal(X):- hombre(X).ciudad(atenas).ciudad(siracusa).vive(socrates,atenas).vive(solon,atenas).vive(pericles,atenas).vive(arquimedes,siracusa).nacio(solon,-634).nacio(pericles,-495).nacio(arquimedes,-287).sonConciudadanos(P1,P2):- vive(P1,C), vive(P2,C).IndividuosLos individuos son aquellas cosas sobre las que versa el conocimiento que queremos expresar. En el ejemplo aparecen varios individuos: socrates, atenas, solon, arquimedes, siracusa, -634, -287. Individuo es cualquier entidad acerca de la cual nos interese estudiar sus caractersticas o sus relaciones con otros individuos. P.ej. si hiciramos un sistema para controlar correlatividades entre las materias de la facultad, tendramos un individuo para representar cada materia. Los individuos se dividen en Individuos simples: los tomos (como solon, atenas, siracusa) y los nmeros son individuos simples. Ver Paradigma Lgico - individuos simples Individuos compuestos: tienen otros individuos adentro, los componentes, y se pueden ver o bien como una unidad o bien acceder a cada componente mediante pattern matching. Ver Paradigma Lgico - individuos compuestos.PredicadosLos predicados son las cosas que queremos decir (o predicar, je) acerca de los invividuos. En este ejemplo los predicados que aparecen se llaman mortal, hombre, vive, nacio, sonConciudadanos.A la cantidad de parmetros que lleva cada predicado la llamamos su aridad. En el ejemplo, los predicados hombre, mortal y ciudad tienen aridad 1, mientras que vive y sonConciudadanos tienen aridad 2. A partir de su aridad podemos separar los predicados en: Propiedades : Son los predicados de aridad 1, que expresan caractersticas de individuos. Por ejemplo, ser mortal es una propiedad. Relaciones : Son los predicados de aridad mayor a 1, que expresan relaciones entre individuos. Por ejemplo, saber dnde vive alguien es una relacin entre una persona y una ciudad.Usualmente haremos referencia a un predicado en particular, no slo mediante su nombre sino tambin su aridad (por ejemplo hombre/1), ya que podran haber predicados con el mismo nombre pero distinta aridad y seran totalmente independientes entre ellos.Volviendo al ejemplo del sistema de correlatividades, seguramente tendra un predicado que relacione cada alumno con cada materia que curs, y otro que indique la correlatividad entre dos materias relacionando una materia con cada requisito.ClusulasCada una de las sentencias = unidades de informacin de una base de conocimiento. Las clusulas deben terminar con un punto . El ejemplo tiene 15 clusulas. Cada clusula participa en la definicin de un predicado, define ciertos casos para los que un predicado se verifica. En el ejemplo: las clusulas 1 a 4 definen por extensin el predicado hombre/1. la clusula 5 define el predicado mortal/1, indicando que cualquier individuo que sea hombre, es mortal. las clusulas 6 y 7 definen por extensin el predicado ciudad/1 etc..Cada clusula puede ser un hecho o una regla.Un hecho hace una afirmacin incondicional (no depende de ninguna condicin para ser cierta), generalmente sobre un individuo particular.En el ejemplo todas las clusulas son hechos salvo las que definen los predicados mortal/1 y sonConciudadanos/2. Sintcticamente, los hechos son las clasulas que no incluyen el smbolo :- .Una regla define una implicacin, es decir que define que si se cumplen ciertas condiciones, entonces un predicado se verifica para ciertos individuos.La clusula mortal(X):-hombre(X). sirve para determinar de forma general (por comprensin, no por extensin) si un cierto X es mortal. Esta definicin indica que si se cumple la condicin hombre(X) entonces el predicado mortal/1 se cumple para ese mismo X. Una regla se compone de una cabeza (mortal(X)) y un cuerpo (en este caso es solamente hombre(X)), unidos por el smbolo :- que denominamos cuello. Si vemos una regla como una implicacin con antecedente y consecuente, est invertida respecto a lo que se vio al estudiar lgica: la cabeza es el consecuente, el cuerpo es el antecedente.El predicado sonConciudadanos/2 tambin se define con una regla, slo que un poco ms compleja porque depende de una conjuncin entre dos condiciones ms sencillas.ConsultasSon la forma de usar un programa en lgico, se hace una consulta, y se obtiene una o varias respuestas.Existen dos tipos de consulta:Individualesse hacen sobre individuos especficos. Por ejemplo:?-mortal(socrates).?-sonConciudadanos(socrates,solon).ExistencialesSe verifica si existe algn individuo que satisfaga la consulta. Adems, Prolog a veces nos sabe dar &quot;ejemplos&quot; de individuos que hacen verdadera la consulta. Por ejemplo:?-mortal(X).?-sonConciudadanos(X,Y).?-sonConciudadanos(solon,Y).En el segundo caso cada respuesta es un par de conciudadanos (o sea, de individuos relacionados por el predicado sonConciudadanos/2, mientras que en el tercero cada respuesta es un conciudadano de Soln.En este tipo de consultas aparecen variables o incgnitas. Por ese motivo este tipo de consultas tambin son llamadas consultas variables." + +} , + +{ + +"title" : "Paradigma logico", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigma-logico.html", +"date" : "", +"content" : "Este paradigma se basa en los conceptos de lgica matemtica, se basa predicados que caracterizan o relacionan a los individuos involucrados y la deduccin de las posibles respuestas a una determinada consulta.Es un paradigma declarativo. No hay asignaciones destructivas, se trabaja con el concepto de unificacin.Las bases del paradigma Introduccin Nomenclatura lgica Conjuncin y Disyuncin Negacin Existe vs Para TodoModelando la informacin Aritmtica en Prolog Individuos simples Individuos compuestos Trabajo con valoresAlgunas Caractersticas Relevantes Inversibilidad Principio de Universo Cerrado Generacin Mltiples Respuestas Unificacin y Pattern-Matching Polimorfismo en el Paradigma Lgico Recursividad en LogicoPredicados de Orden Superior Orden Superior not forall findall distinct Cmo hacer predicados de orden superiorErrores y preguntas frecuentes Errores frecuentes al programar en lgico Preguntas Frecuentes del Paradigma Lgico Cmo encaro un problema en Lgico?Ms caractersticas Paradigma Lgico - detalles del SWI Prolog Aqu pueden ver otros Lenguajes del Paradigma lgico, adems del Prolog." + +} , + +{ + +"title" : "Paradigmas de programacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/paradigmas-de-programacion.html", +"date" : "", +"content" : " Qu es un Paradigma de ProgramacinLos paradigmas Paradigma Lgico Paradigma Funcional Paradigma de ObjetosConceptos Transversales Abstraccin Declaratividad Expresividad Orden Superior Transparencia Referencial, Efecto de Lado y Asignacin Destructiva Polimorfismo Representacin de informacin Estrategias de Evaluacin Esquemas de Tipado Mquina VirtualY algunas discusiones interesantes que surgieron alrededor de estas ideas: Declaratividad vs. Expresividad Diferencias entre polimorfismo, abstraccin y encapsulamientoMaterial de lectura extraConcepts, Techniques and Models of Computer Programming" + +} , + +{ + +"title" : "Parsers monadicos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/parsers-monadicos.html", +"date" : "", +"content" : "Este artculo est en construccin.Un uso muy simptico para el concepto de mnadas es la posibilidad de construir parsers a partir de ellas. Esto es posible en diferentes lenguajes, como Haskell y Scala. Este artculo intenta compendiar algo de informacin al respecto.Parsers Mondicos en ScalaAlgunos artculos interesantes: Este es el ejemplo ms simple y consciso que encont: http://www.scala-lang.org/node/808 http://debasishg.blogspot.com/2008/04/external-dsls-made-easy-with-scala.html muestra cmo construir un dsl en scala, partiendo de algo de teora acerca de parser combinators." + +} , + +{ + +"title" : "Patrones de comunicacion entre componentes", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/patrones-de-comunicacion-entre-componentes.html", +"date" : "", +"content" : "AVISO @DeprecatedEste contenido est desactualizado, se reemplaza por el apunte que aparece en https://docs.google.com/document/d/1EVPwqFyq2TW5Z5_VUeWdh9yLesxPBbSBzke2jHNURuk/edit?usp=sharingMemoria compartida (shared memory)La memoria compartida es un espacio comn de datos en el que mltiples componentes (por ejemplo: procedimientos) pueden leer y escribir informacin. Implementaciones tpicas de memoria compartida son las variables globales o las bases de datos como herramienta de integracin entre componentes.EjemploA continuacin podemos ver un ejemplo de una pila programada en C utilizando esta forma de compartir informacin:#include&lt;stdio.h&gt;#defineSIZE50intcurrent,stack[SIZE];voidinit(){current=0;/*initializecurrent*/}voidpush(inti){current++;if(current==(SIZE)){printf("StackOverflow.&#92;n");exit(1);}stack[current]=i;}intpop(void){if(current==0){printf("StackUnderflow.&#92;n");exit(1);}current--;returnstack[current+1];}intmain(void){intvalue;init();push(1);push(2);printf("Firstvalueontopis%d&#92;n",pop());printf("Secondvalueontopis%d&#92;n",pop());printf("Thirdvalueontopis%d&#92;n",pop());printf("end&#92;n");return0;}ConsecuenciasAlgunas consecuencias de esta forma de compartir informacin son: No hay un mecanismo sencillo para saber qu procedimientos incluyen referencias a las variables globales y No es posible tener dos pilas simultneamente, en caso de intentarlo se mezclara la informacin de ambas. La modificacin de cualquiera de las operaciones que acceden a la estructura de datos implica revisar su buen comportamiento en relacin con todas las dems (que, como se dijo antes, puede no ser posible saber exactamente cules son). Lo mismo ocurre si se desea modificar la estructura de los datos compartidos.En el caso general la memoria compartida representa un grado alto de acoplamiento ya que a priori no es posible saber qu componentes modifican o leen qu parte de los datos. En sistemas donde la informacin compartida est sostenida en un motor de bases de datos (por ejemplo RDBMS), estos pueden mitigar parcialmente este problema al implementar esquemas de seguridad que restrinjan en parte el acceso a los datos a slo la parte necesaria de cada componente.Por otro lado, existen tecnologas que permiten definir variables con alcance o scopes ms limitado que global, reduciendo de esta manera el acoplamiento nicamente a los componentes que tienen acceso al scope especfico. Un caso particular de scope son las variables de instancia de un objeto, como se muestra en el ejemplo siguiente.Ejemplo: JavapublicclassStack{publicstaticfinalSIZE=50;privateintcurrent;privateint[]stack=;publicStack(){current=0;stack=newint[50];}publicvoidpush(inti){current++;if(current==(SIZE)){System.out.println("StackOverflow.&#92;n");System.exit(1);}stack[current]=i;}publicintpop(){if(current==0){System.out.println("StackUnderflow.&#92;n");System.exit(1);}current--;returnstack[current+1];}publicstaticvoidmain(){Stacks=newStack();s.push(1);s.push(2);System.out.println("Firstvalueontopis%d&#92;n",s.pop());System.out.println("Secondvalueontopis%d&#92;n",s.pop());System.out.println("Thirdvalueontopis%d&#92;n",s.pop());System.out.println("end&#92;n");return0;}}Call &amp; ReturnEn el mecanismo de call &amp; return la comunicacin se da entre un componente invocante o llamador (caller) que invoca o referencia a otro componente invocado o llamado (callee). Si bien el flujo de informacin es bidireccional, es asimtrico: El componente invocado puede recibir parmetros, que le permiten al invocante transferirle informacin mediante argumentos. En el caso general el componente invocado puede producir un valor de retorno, mediante este mecanismo se logra la bidireccionalidad de la comunicacin. En algunas tecnologas pueden existir limitaciones que restringen el uso de valores de retorno, en ese caso la comunicacin ser unidireccional.Ejemplo puroEl ejemplo ms preciso de esta idea se encuentra en los lenguajes funcionales puros, es decir, sin la posibilidad de efecto. La ausencia de efecto obliga a que toda la comunicacin sea por medio de los parmetros.typeStack=[Int]empty::Stackempty=[]push::Int-&gt;Stack-&gt;Stackpushis=i:spop::Stack-&gt;(Int,Stack)pop[]=error"StackUnderflow.&#92;n"pop(i:s)=(i,s)discard=snd.poppeek=fst.poptest1=peek$discard$push2$push1$emptyConsecuenciasSi bien la comunicacin puede ser bidireccional, el conocimiento (y por lo tanto el acoplamiento) es a priori unidireccional, es decir, el componente llamado no tiene ningn conocimiento de el origen del mensaje y an puede devolver informacin sin tener conocimiento del destino de la misma.La aclaracin a priori en el prrafo anterior se explica porque en lenguajes con efecto (es decir, la mayora de los lenguajes que usamos habitualmente en la industria) los parmetros podran ser modificados dentro del componente. Para estudiar el acoplamiento en estos contextos debemos determinar cunto debe saber el componente llamado acerca de sus parmetros, por ejemplo si puede o no modificarlos. Esto a su vez depende del tipo de pasaje de parmetros que utilicemos (por ejemplo, pasaje de parmetros por copia o pasaje de parmetros por referencia). En el caso de pasaje por parmetros por referencia, la modificacin del parmetro recibido puede ser un mecanismo adicional de comunicacin entre los componentes.TODO: Este ejemplo no inicializa correctamente la pila y tira error.Ejemplo con Call-By-Reference#include&lt;stdio.h&gt;#include&lt;stdlib.h&gt;#defineSIZE50typedefstructstack{intcurrent,stack[SIZE];}stack;stack*empty(){stack*s=(stack*)malloc(sizeof(stack));returns;}voidpush(stack*s,inti){s-&gt;current++;if(s-&gt;current==SIZE){printf("StackOverflow.&#92;n");exit(1);}s-&gt;stack[s-&gt;current]=i;}intpop(stack*s){if(s-&gt;current==0){printf("StackUnderflow.&#92;n");exit(1);}returns-&gt;stack[s-&gt;current--];}intmain(void){stack*s=empty();push(s,1);push(s,2);printf("Firstvalueontopis%d&#92;n",pop(s));printf("Secondvalueontopis%d&#92;n",pop(s));printf("Thirdvalueontopis%d&#92;n",pop(s));printf("end&#92;n");return0;}ExcepcionesContinuationsclassMyCPSStack{defelements=[]staticempty(yield){yield(newMyCPSStack())}voidpush(element,yield){yield(newMyCPSStack(elements:[element]+elements))}voidpop(yield){if(elements.empty)thrownewException("StackUnderflow")yield([elements.head(),newMyCPSStack(elements:elements.tail())])}defdiscard(yield){pop({yield(it[1])})}//itsignifica"el(nico)argumentoquerecibeestebloquedecdigo"defpeek(yield){pop({yield(it[0])})}StringtoString(){returnelements.toString()}}MyCPSStack.empty({it.push(1,{it.push(2,{it.discard({it.peek({printit})})})})})http://en.wikipedia.org/wiki/Continuation-passing_style http://en.wikipedia.org/wiki/Callback_(computer_science)EventosMensajes asincrnicos" + +} , + +{ + +"title" : "Pattern matching polimorfismo y diseno", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/pattern-matching--polimorfismo-y-diseno.html", +"date" : "", +"content" : " Incorporar declaraciones de operaciones vs incorporar definiciones de operaciones pattern matching no es tan solo un switch jerarquias acotadas vs jerarquias abiertas ejemplos en scala" + +} , + +{ + +"title" : "Pattern matching en haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/pattern-matching-en-haskell.html", +"date" : "", +"content" : "Pattern Matching es el concepto asociado al chequeo estructural de un dato respecto de una estructura esperada. El uso de pattern matching tiene la ventaja de simplificar mucho la codificacin, ya que slo escribimos la forma de lo que esperamos y podemos desglosar los componentes de estructuras complejas.Una desventaja asociada a usar pattern matching en vez de funciones para acceder a los elementos de las tuplas es que nuestro cdigo se ver muy afectado ante un cambio en las estructuras manejadas. El simple hecho de agregar un elemento ms a la tupla que representa a nuestro elemento de dominio provocar un cambio en el tipo del mismo y el mismo se propagar en todos los lugares donde se haya utilizado esta estructura directamente.Ejemplos de matcheoCon nmeros y stringsSi queremos saber si el nombre de un da de la semana es fin de semana podemos hacer:esFinDeSemanadia=dia=="Sbado"||dia=="Domingo"Sin embargo esta otra definicin tambin es vlida:esFinDeSemana'"Sbado"=TrueesFinDeSemana'"Domingo"=TrueesFinDeSemana'_=FalseLa ltima definicin es necesaria, ya que a diferencia del paradigma lgico, no contamos con el principio de universo cerrado y si slo definimos esFinDeSemana para Sbado y Domingo y consultamos por otro da, Haskell nos mostrar un error porque el patrn no calza con ningn elemento del dominio esperado. Para que esta funcin funcione correctamente es importante que el encabezado con la variable annima, que matchea con cualquier patrn, sea la ltima definicin de esFinDeSemana, de lo contrario no habr ningn elemento del dominio cuya imagen pueda ser True (por unicidad).Ac tenemos un ejemplito recursivo tpico para pattern matching con nmeros:factorial0=1factorialn=n*factorial(n-1)Para evitar loops infinitos, es importante poner el caso base primero para que matchee con el 0, ya que la variable n tambin matcheara con este valor.Con tuplasSi tengo los valoresv1=(2,5)v2=(3,5)v3=(8,5)El patrn (x,5) matchea con los tres valores.Tambin el patrn (x,y) matchea con los tres valores.Tambin el patrn (_,5) matchea con los tres valores.Tambin el patrn (_,_) matchea con los tres valores.Tambin el patrn unaTupla matchea con los tres valores.Con listasAhora, si tengo una listalista1=[(2,5),(5,3),(3,3)]lista2=[(2,5)]El patrn (x,5) no matchea con lista1 ni con lista2. Es una tupla, no una lista! Antes de tratar de matchear, Haskell nos va a tirar un error de tipos.El patrn (x:xs) matchea con lista1, siendo x = (2,5) y xs = [(5,3),(3,3)] y matchea con lista2, siendo x = (2,5) y xs = []El patrn [x] no matchea con lista1 porque tiene ms de un elemento, pero s matchea con lista2, siendo x = (2,5)El patrn (x:_) matchea con lista1, siendo x = (2,5) y matchea con lista2, siendo x = (2,5)El patrn (x:y:_) matchea con lista1, siendo x = (2,5) e y = (5,3), y no matchea con lista2 porque slo tiene un elementoEl patrn unaTupla matchea con lista1 siendo unaTupla = [(2,5),(5,3),(3,3)] y matchea con lista2 siendo unaTupla = [(2,5)]. Es slo un nombre de variable, con lo cual no restringe realmente el tipo del valor para que sea una tupla.Con data(En algunos cursos no se da data, para ms informacin ver ac: Data: Definiendo nuestros tipos en Haskell) Suponiendo que tensdataCoordenada=CoordIntInt(el tipo es Coordenada y el constructor es Coord)Donde se puede aplicar la misma idealista1=[Coord25,Coord53,Coord33]lista2=[Coord25]El patrn (Coord x 5) no matchea con lista1 ni con lista2. Es una Coordenada, no una lista! Antes de tratar de matchear, Haskell nos va a tirar un error de tipo.El patrn (Coord x y:restoCoords) matchea con lista1, siendo x = 2, y = 5 y restoCoords = [Coord 5 3,Coord 3 3] y matchea con lista2, siendo x = 2, y = 5 y restoCoords = []El patrn [x] no matchea con lista1 pero si matchea con lista2, siendo x = Coord 2 5El patrn (x:_) matchea con lista1 y matchea con lista2 siendo x = Coord 2 5El patrn (x:y:_) matchea con lista1 siendo x = Coord 2 5 y y = Coord 5 3 pero no matchea con lista2El patrn unaTupla matchea con lista1 y matchea con lista2 porque no es ms que una variable sin ninguna restriccin despus de todoPatrones con sinnimos (at Pattern)Usamos este patrn para definir un sinnimo, o sea necesito por un lado el patrn para tomar algunos de sus componentes y por otro todo junto para la hacer otra cosa, pongamos un par de ejemplos:ordenada[_]=Trueordenada(x1:x2:xs)=x1&gt;x2&amp;&amp;ordenadax2:xsPuede mejorarse sutilmente con un sinnimo.ordenada[_]=Trueordenada(x1:xs@(x2:_))=x1&gt;x2&amp;&amp;ordenadaxsOtro ejemplo, entre dos complejos representados con tuplas, obtener el que tiene mayor parte real:mayorParteReal(a@(a1,_))(b@(b1,_)) |a1&gt;b1=a`|otherwise=bY otro con listas por comprensin:promedioDeAprobadosalumnos=promedio[promedionotas|alumno@(_,notas)&lt;-alumnos,aproboalumno]Sobre la Variable AnnimaLa variable annima _ (guin bajo) funciona, en trminos de matcheo, como una variable comn:esCero0=TrueesCerox=FalseEs lo mismo que decir:esCero0=TrueesCero_=FalseDe hecho, esta ltima opcin es mejor, porque ayuda a la expresividad: si la variable no se usa en la devolucin (a la derecha del igual, a la derecha de la guarda) entonces mejor ni ponerle nombre. Por ejemplo:anioActual=2014edad(nombre,anioNac,cantPerros)=anioActual-anioNacEn ese caso la funcin edad recibe una tupla pero a la derecha, en la definicin de la funcin, no hace faltan el nombre y el cantPerros. Entonces, usamos variables annimas:edad(_,anioNac,_)=anioActual-anioNacError comn con Variables AnnimasMuchas veces pensamos que no necesitamos una variable, cuando en realidad s la usamos a la derecha del igual. Por ejemplo, si queremos tomar esa definicin de persona como una tupla de tres, y agregarle perros a la persona, debemos devolver a una persona, pero cambiando slo la cantidad de perros.Esto es errneo:agregarPerroscant(_,_,cantPerros)=(_,_,cantPerros+cant)Son variables annimas! Si quiero usarlas a la derecha del igual ( sea, si quiero que sean parte de lo que devuelvo) entonces tengo que usar variables comunes.Esto est bien:agregarPerroscant(nombre,anioNac,cantPerros)=(nombre,anioNac,cantPerros+1)" + +} , + +{ + +"title" : "Pepita", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/pepita.html", +"date" : "", +"content" : "PepitaEn muchos ejemplos en esta Wiki surge la figura de Pepita, la golondrina. Pero quin es Pepita, de dnde viene y para qu est ac?Caractersticas BsicasPepita es una golondrina, que tiene un cierto nivel (medido en Joules) variable de energa, y sabe hacer al menos dos cosas: volar y comer, aunque a veces y segn el ejercicio se le agregan comportamientos extra: volar hacia ciertos lugares, llevar paquetes, etc.VolarCuando vuela, consume una cierta cantidad arbitraria de energa. En ocasiones este mensaje est parametrizado segn la cantidad de kilmetros que vuela; en ese caso la prdida de energia es una funcin lineal de esta distancia. Por ejemplo: pepita consume un joule para cada kilmetro que vuela, ms 10 joules de costo fijo en cada vueloComerPepita come alpiste, y cuando lo hace, su energa se incrementa linealmente en funcin de la cantidad de gramos de alpiste consumidos. Por ejemplo: cuando come, adquiere 4 joules por cada gramo que comeHistoriaPepita fue creada por Carlos Lombardi hacia 2004, y termin de cobrar forma con los aportes de Germn Leiva y Nico Passerini.Links Externos Ms ejercicios: https://docs.google.com/document/d/1DQNuJwO3m6o_0-31tld94eJKJSQQ2TsjqBBY_rOVho4/edit Si aprendiste objetos con Pepita: https://www.facebook.com/pepitaesunaformadevida?fref=ts" + +} , + +{ + +"title" : "Pharo para programadores ozonosos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/pharo-para-programadores-ozonosos.html", +"date" : "", +"content" : "La migracin desde trabajar con Ozono a pasar a la versin full de Pharo puede ser complicado en ciertos sentidos pero ms o menos es lo mismo pero tenemos que tener en cuenta las diferencias.Clases vs. ObjetosLa primer diferencia que tenemos en este nuevo ambiente es que Pharo esta centrado en las clases y no en los objetos.Como ya vimos en las clases tericas, los objetos ya no los vamos a crear uno por uno sino que vamos a crear los objetos a partir de clases.Por lo tanto, la forma que tiene Pharo (y muchos otros lenguajes orientados a objetos) es organizarse alrededor clases.System Browser, el centro de nuestro desarrolloPara comenzar vamos a necesitar una imagen de Pharo, cualquier imagen nos va a servir; pueden seguir usando la que tiene instalada Ozono :D.Nuestro principal amigo en el desarrollo con Pharo va a ser el System Browser. Este lo encontramos dentro del men principal de Pharo.Esto nos va a abrir la siguiente ventana (es bastante compleja para decirle ventanita).Secciones del System BrowserEsta ventana se divide en distintas secciones, esta ventana es central, presenta mucha mucha mucha informacin por eso vamos a analizarla por secciones.Estas Secciones son: Categorias de clases: en esta seccin aparece una forma de categorizar las clases. Las categoras de las clases en Pharose llaman Packages, estos paquetes de clases pueden contener una o ms subcategoras dentro. Clases: una vez que selecciono un paquete se me van a mostrar las clases que estn definidas en ese paquete. Porque algunasaparecen con signo de admiracin (!), porque no tienen escrita la documentacin que explica que hace la clase. Categoras de Mtodos: cuando selecciono una clase se me van a mostrar los mtodos que tiene definida esa clase. Estosmtodos pueden estar clasificados en distintas categoras, esto es muy til como forma de documentacin y suma mucho valor cuando comienza a crecer mi programa. Metodos: al ir navegando las categoras de los mtodos van a ir mostrndome la lista de mtodos de esa clase en la categoraseleccionada. rea de Edicin de Cdigo: En esta rea de la ventana es donde se realiza la edicin del cdigo. Si elegimos un mtodo vamos aver el cdigo de ese mtodo, pero si elegimos una clase nos muestra un cdigo raro. No entremos en pnico, ese cdigo es la definicin de la clase, ya vamos a entrar en el detalle de como hacerlo.Por ahora debemos entender las distintas secciones del System Browser pronto vamos a ver para que se usa cada cosa con un ejemplo.WorkspacesBueno, bueno, todo muy bonito pero a mi me gustaba enviar mensajes a mis objetos. Esto lo perdimos, esto es una mierda. No, no perdimos nada!!!La forma de enviar mensajes y probar nuestro programa van a ser nuestros bonitos workspace (despus vamos a hablar de tests, pero eso es otra versin mucho ms cheta aunque menos interactiva).Para crear un workspace lo hacemos desde el men principal de Pharo, es el mismo que usamos inicialmente.Adems podemos tener muchos workspace abiertos.Los workspace de Pharo se usan de la misma manera que los de Ozono que ya usamos previamente. Pero con una variacin interesante, podemos definir variables dentro del workspace. Estas variables son locales al workspace. Para definirlas debemos usarlas directamente, asignandole un valor. Cuando evaluemos esa lnea va a crearse la variable.Atencin, los workspace no se van a guardar solitos como en Ozono, tenemos que guardarlos a mano. Normalmmente no nos vamos a preocupar por esto ya que el cdigo que pongamos en el workspace es para pruebas rpidas. Si queremos guardar algo que vamos a probar varias veces nos sirve la idea de Tests, ya la vamos a ver; pero por ahora con el workspace nos sirve.Los workspace se guardan como archivos de texto con extensin .ws, para poder guardar y cargar estos archivos tenemos que usar la flechita que esta a la derecha y arriba del workspace.Un ejemplo Paso a PasoPara poder mostrar como se usa Pharo, vamos a implementar el siguiente ejemplo.Vamos a tener que construir un sistema para administrar camiones en una empresa de logstica. De cada camin vamos a saber su capacidad en kilos y su carga actual, y adems podemos saber si el camin esta lleno o no.Al analizar y plantear una solucin al problema, identificamos que todos los objetos camiones tienen el mismo comportamiento; por lo que extrajimos la siguiente clase:Tenemos que recordar que la solucin se da con los objetos que representan los camiones, las clases sirven para crear muchos camiones iguales, o sea se comportan todos juntos.Recordemos un poquito la forma de comunicacin con los diagramas de clase. Este rectngulo que representa la clase tiene 3 secciones. En la superior va el nombre de la clase. En la del medio los distintos atributos que tienen los objetos creados con esta clase. Y en la inferior los mensajes que entienden los objetos creados con la clase.Perfecto ya sabemos que es lo que tenemos que hacer, ahora vamos a implementarlo en Pharo!Creacin de PaquetesPara comenzar tenemos que crear un paquete nuevo dentro de Pharo. Todas las clases de Pharo estan definidas dentro de un paquete, es muy recomendable que creemos un paquete para cada uno de los ejercicios o problemas o sistemas que creemos.Para crear un paquete tenemos que hacer click derecho sobre el sector de paquetes del System Browser y elegir la opcin Add Package. Esta opcin nos va a preguntar el nombre del nuevo Paquete.Podemos ponerle el nombre que queramos, pero existe una convencin que se usa en todos lados y que Pharo va a usar para presentarnos la informacin. Esta convencin es separar las palabras con guin del medio.En este caso vamos a crear el paquete Logistica.Una aclaracin importante, es que aunque es probable que Pharo se banque nombres con acentos o o cualquier caracter UTF-8, a los programadores nos gusta obviar los acentos y las ; porque siempre siempre siempre van a traer problemas.Cuando creamos el paquete nos debera quedar algo as:Creacin de ClasesYa tenemos nuestro paquete creado, por ahora esta vaci y triste y solo; por lo que vamos a comenzar creando la clase Camin.Para crear una clase tenemos que hacer las siguientes operaciones: Hacer click sobre el paquete donde va a vivir nuestra nueva clase. Ingresar la definicin de la clase en el rea de Edicin de Cdigo, ahora vamos a hablar de que hay que escribir ah. Aceptar la definicin, ya sea haciendo Ctrl+S o haciendo botn derecho y darle la opcin Accept.Definicin de una ClaseLas clases en cualquier ambiente de Smalltalk se definen a partir de un envi de mensaje. Nadie en la vida se acuerda este mensaje que hay que mandar a la clase Object, pero al hacer click sobre un paquete la herramienta ya nos propone un template:Objectsubclass:#NameOfSubclassinstanceVariableNames:''classVariableNames:''category:'Logistica'La definicin de nuestra clase Camion es la siguiente:Objectsubclass:#LgCamioninstanceVariableNames:'capacidadcarga'classVariableNames:''category:'Logistica'Si se fijan no es tan tan loca.Las cosas que voy a modificar son: El nombre de la clase, es eso que esta despus del numeral Las variables de instancia, ac agrego dentro del string cada uno de los nombres de las variables de instancia separados por un espacio.En este caso tengo dos variables de instancia, capacidad y carga. Nombre de la categora donde esta clase, ac ya me pone la que corresponde al paquete donde estoy parado, pero siempre lo puedo cambiar.Un minuto cerebrito, ac dijimos que ibamos a crear la clase Camion y vos le pusiste LgCamion; me estas cargando o todas las clases comienzan con Lg???Ninguna de las dos cosas, es un prefijo que identifica a nuestro paquete; como cree un paquete llamado Logistica defin que el prefijo que identifique a las clases dentro de este con el prefijo Lg.Esto lo tenemos que hacer porque Pharo no tiene espacios de nombres independientes, o sea no puedo tener dos clases con el mismo nombre, si quisiera crear una clase con el mismo nombre de otra que existe, voy a pisar la original. Por eso vamos a generar nombres nicos teniendo un prefijo para el paquete y el nombre de la clase.Si estamos muy muy muy seguros que no existe otra clase que se llame Camion, podra ponerle ese nombre. Pero yo debo contarle el estandard.Despus de crear la clase nos debera quedar algo as:Atencin, no nos preocupemos por ese signo de admiracin rojo. Ya lo dijimos, pero lo recuerdo, es un indicativo que la clase no esta documentada. Nada importante, por ahora, es algo que nos debera importar.Definicin de MtodosYa definimos nuestra clase ahora debemos agregarle mtodos.Para poder agregar un mtodo a una clase, tenemos que tener seleccionada la clase donde lo vamos a definir y hacer click sobre la categora del mtodo que vamos a generar; si no tenemos la categora, la podemos crear o hacer click en no messages que es la que tengo cuando esta vaca o en all si ya tiene alguna.Cuando hacemos esto la seccin de edicin de cdigo nos va a ofrecer el template, esto no es solo necesario para que nos muestre el template, sino que lo tengo que hacer para que Pharo sepa donde voy a meter el mtodo.Entonces vamos a escribir el cdigo de nuestro primer mtodo, lo que vamos a hacer es un mensaje para que el camin nos devuelva su capacidad:capacidad^capacidadPara guardar el mtodo creado, tenemos que hacer CTRL+s o botn derecho y elegir la opcin Accept.Cuando hacemos esto, nos queda el siguiente resultado.Probando nuestros ObjetosYa tenemos creada nuestra clase, ahora probemos los objetos que creamos. Para poder crear objetos y mandarles mensajes necesitamos usar un workspace.En un nuevo workspace vamos a escribir el siguiente cdigo.unCamion:=LgCamionnew.unCamioncapacidad.Podemos ir ejecutando lnea a lnea. La primera nos conviene ejecutarla con un Do-It (o haciendo Ctrl+d), ya que es una lnea que tiene efecto de lado. Esta lnea crea un nuevo objeto a partir de la clase LgCamion y lo asigna a la variable local unCamion.La 2da lnea la vamos a ejecutar con un Print-It (o haciendo Ctrl+p), ya que es una expresin que va a devolver la capacidad del camin.Dando como resultado lo siguiente:Pero porque cuando evaluamos la 2da expresin nos devuelve nil? Bueno, porque todas los atributos de un objeto arrancan en nil.Por eso debemos agregarle el mtodo para poder establecer los valores de los objetos. Vamos a agregar los siguientes mtodos a la clase LgCamion:capacidad:unValor.capacidad:=unValor.carga^carga.carga:unValorcarga:=unValor.Adems vamos a definir el mtodo para responder al mensaje estasLleno.estasLleno.^capacidad=carga.Entonces una vez que tenemos este mensaje podemos hacer una prueba ms interesante con el siguiente workspace.unCamion:=LgCamionnew.unCamioncapacidad:1000.unCamioncarga:1000.unCamionestasLleno.Este workspace ya nos permite probar una variante, que podemos ir modificando para probar nuestros objetos. Una alternativa interesante para esto, es poder crear tests unitarios.Como guardar mis programasEn Pharo, los programas se guardan dentro de la imagen, o sea tengo que ir guardando la imagen con el cdigo y los objetos de mis programas.Exportar a un .stAdems puedo exportar los paquetes como un archivo .st. Para realizar esto podemos hacerlo desde el System Browser y con el botn derecho sobre un paquete y eligen la opcin File Out.Al hacer esto se genera un archivo con el nombre del paquete y la extensin .st que incluye todo el cdigo fuente de las clases del paquete.Importar un .stPara poder importar un archivo .st lo ms fcil es arrastrar el archivo sobre una imagen de Pharo que se encuentre corriendo y al soltarlo elegir la opcin FileIn Entire File y listo ya lo va a cargar en la imagen." + +} , + +{ + +"title" : "Script mapeo manual Objetos / Relacional", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/phm-script-mapeo-manual-or.html", +"date" : "", +"content" : " Presentacin del ejercicio de los partidos de ftbol modelo de objetos traslacin al modelo relacional Creamos las tablas (DDL: Data Definition Language) Insertamos valores desde el modelo relacional (mediante scripts de manipulacin de datos o DML) O -&gt; R o R -&gt; O? Crear Juego de datos en alguna de las dos tecnologas Intro a JDBC. Driver o controlador como el componente que permite a nuestra aplicacin (en este caso JDK) interactuar con un motor de base de datos. Conexin Externalizacin a un archivo / Encriptacin Pool de conexiones Statement Statement de consulta que devuelve Resultsets Statement de insercin, eliminacin o actualizacin que slo implica ejecucin Prepared Statement Mapeo manual Disear objetos que modelen slo la estructura (ej: EJB 2.x) vs. usar los objetos de dominio No hay razn para mantener una doble jerarqua de objetos sin comportamiento Hidratacin del grafo de objetos, se segmenta por caso de uso cuando quiero saber quin gan, no necesito saber los que jugaron, slo el resultado cuando quiero saber si un jugador estuvo en un partido, tengo que bajar el grafo de objetos de Equipo, Resultado, Formacin hasta los jugadores relacionados con la formacin Ventajas mayor control sobre el algoritmo podemos armar queries especficos (manipular SQL puro) Contras hay que encargarse de todo: es tedioso y repetitivo dificulta la reutilizacin de ideas Tests unitarios el juego de datos se instancia por afuera esto implica una dependencia que sale del ambiente de objetos si alguien se olvida de correr el script en la base de datos, no funcionan los tests si alguien cambia el juego de datos, no funcionan los tests mientras nadie modifique la base, los tests funcionan claro, no hay efecto colateral: los tests slo son de lectura. Ms adelante veremos tcnicas para que los tests puedan seguir manteniendo unitariedad (e - independencia entre s). Resumen" + +} , + +{ + +"title" : "Script temario MongoDB", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/phm-script-mongodb.html", +"date" : "", +"content" : "Tutorial Tutorial de TutorialspointConceptos a aprenderSin duda la documentacin oficial de MongoDB es el mejor sitio para aprender Modelado de datos: un documento Constraints: cmo validar Caractersticas del diseo de datos de un documento Ejemplo de One-To-Many con documentos embebidos Ejemplo de One-To-Many normalizando los documentos Operaciones bsicas sobre un documento Queries de seleccin de datos Optimizacin de Queries Queries en ambientes distribuidos Definicin de ndices Text search Aggregation Queries de actualizacin de datos Actualizacin en ambientes distribuidos Performance en los queries de actualizacin Tcnica de MapReduce" + +} , + +{ + +"title" : "Programacion con herramientas modernas", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/phm-temario.html", +"date" : "", +"content" : "Software Entorno Xtend (en Eclipse) JDK vs. JRE Maven Cmo trabajar con TravisPginas Script Mapeo manual Objetos / Relacional Script MongoDBLinks Sitio oficial de la materia" + +} , + +{ + +"title" : "Polimorfismo en el paradigma de objetos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/polimorfismo-en-el-paradigma-de-objetos.html", +"date" : "", +"content" : "El polimorfismo en el paradigma de objetos se define como la capacidad que tiene un objeto de poder tratar indistintamente a otros que sean potencialmente distintos. Cuando hablamos de que un objeto trate a otros, estamos hablando de que interacten a travs de mensajes.Lo que nos va a interesar al programar es ver a un objeto desde un punto de vista externo (cuando mandamos mensajes) y desde un punto de vista interno (cuando implementamos el comportamiento que queremos). Al punto de vista externo, que slo incluye el comportamiento que exhibe (los mensajes que entiende) le vamos a decir interfaz.Y Como puede un objeto tratar indistintamente (o a partir de ahora, polimorficamente) a otros?Mandandole los mismos mensajes!Entonces, podemos decir que un objeto trata polimrficamente a otros cuando les enva a ambos exactamente los mismos mensajes, sin importarle cual es cual y ellos pueden responder ya que tienen una interfaz comn.Cuntos objetos son necesarios como mnimo para que exista el polimorfismo?Tres: El objeto que usa y los (como mnimo) 2 que son usados.Cules son las condicines necesarias para que dos objetos sean polimrficos? - que un tercero quiera usarlos indistintamente - que entiendan los mensajes que ese tercero quiere enviarlesCabe resaltar que para que dos objetos sean polimrficos en un contexto determinado (es decir, ante el tercero, en un momento particular), es condicin necesaria que entiendan los mismos mensajes. Sin embargo, para que puedan ser usados indistintamente, adems de ello, deben comportarse ante tal envo de mensaje, de una forma similar desde el punto de vista del dominio, produciendo efectos similares, devolviendo objetos tambin polimrficos entre s, etc." + +} , + +{ + +"title" : "Polimorfismo en el paradigma logico", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/polimorfismo-en-el-paradigma-logico.html", +"date" : "", +"content" : "El polimorfismo permite obtener soluciones ms genricas, que sean vlidas para diferentes tipos de datos contemplando las particularidades de cada uno de ellos. En general podemos decir que dos cosas son polimrficas cuando desde algn punto de vista comparten un tipo, o sea que pueden ser tratados indistintamente por quienes no les interesen los detalles en los cuales difieren.Si bien todos los predicados pueden recibir cualquier tipo de argumento, muchas veces el uso que se hace de ellos en el interior de las clusulas que lo definen, delimita un rango de tipos de valores que tiene sentido recibir. En lgico no sucede un error si se recibe un dato de tipo diferente a los esperados, sino que directamente la consulta falla por no poder unificar el valor recibido con lo esperado, descartndolo como posible respuesta a la misma.Ejemplo de Polimorfismo usando functoresSi tenemos el siguiente requerimiento: se tiene 3 tipos de vehiculos autos, camiones y bicicletas. Un auto es viejo si su patente es menor a F, un camion es viejo si tiene ms de 60000km o ms de 10 aos, una bicicleta es vieja si la fecha de fabricacion es de ao anterior al 2006Supongamos que nuestra base de conocimiento tiene los siguientes hechos:hoy(fecha(22,12,2008)).vehiculo(auto("A2000")).vehiculo(auto("H2342")).vehiculo(camion(12000,2005)).vehiculo(camion(70000,2003)).vehiculo(camion(30000,1997)).vehiculo(bici(fecha(30,10,2005))).vehiculo(bici(fecha(20,12,2008))).Si quiero hacer una consulta que me diga si todos los vehculos de la base de conocimientos son viejos, cmo hago para manejar el tema de que los datos tienen formas distintas y la lgica asociada a las distintas formas vara?La alternativa infeliz no polimrfica sera hacer algo as:autoViejo(Patente):-Patente&gt;"F".camionViejo(Kilometraje,_):-Kilometraje&gt;60000.camionViejo(_,Anio):-hoy(fecha(_,_,AnioActual)), AnioActual-Anio&gt;10.biciVieja(fecha(_,_,Anio)):-Anio&lt;2006.?-forall(vehiculo(auto(Patente)),autoViejo(Patente)),forall(vehiculo(camion(Kms,Anio)),camionViejo(Kms,Anio)),forall(vehiculo(bici(Fecha)),biciVieja(Fecha)).Para que esto se cumpla todos los vehculos deben cumplir la correspondiente validacin del forall con lo cual estara funcionando como necesitamos, pero la solucin elegida es bastante molesta y repetitiva. Sin contar que si queremos incorporar las motos a nuestra base de conocimientos, la consulta sera an ms larga.La idea del polimorfismo nos viene brbaro en este caso, y lo nico que necesitamos es que exista un predicado esViejo/1 ande con autos, camiones y bicicletas y por ende pueda ser usado de forma genrica por otro predicado o consulta sin tener que pensar en el tipo de vehculo.Ahora, para resolver el requerimiento de forma polimrfica tenemos que hacer el predicado esViejo/1 que se verifique si se cumplen las condiciones explicadas anteriormente. Para ello usaremos varias clusulas que, por medio de pattern matching, se apliquen a cada tipo de vehculo particular.esViejo(auto(Patente)):-Patente&gt;"F".esViejo(camion(Kilometraje,_)):-Kilometraje&gt;60000.esViejo(camion(_,Anio)):-hoy(fecha(_,_,AnioActual)), AnioActual-Anio&gt;10.esViejo(bici(fecha(_,_,Anio))):-Anio&lt;2006.Con esto podemos realizar la consulta que queramos de esta forma:?-forall(vehiculo(Vehiculo),esViejo(Vehiculo)).Podemos decir entonces que el predicado polimrfico es esViejo/1, porque funciona con distintos tipos de vehiculos, y quien lo aprovecha es la consulta del forall que no necesita hacer distinciones sobre los tipos de vehculos, unificando toda la estructura con la variable Vehiculo.Es importante notar que modelar los vehculos con functores nos permite tener individuos ms complejos a que si tuviramos directamente los datos en el predicado:vehiculo(auto,"A2000").Y adems nos permite usar el mismo predicado (vehiculo/1 en este caso) para todos los tipos de vehculos, lo cual se aprovecha principalmente con el camin que tiene ao y kilometraje:vehiculo(auto,"A2000"). % vehiculo/2vehiculo(camion, 12000, 2005). % vehiculo/3Al tener distinta cantidad de valores afecta directamente a la aridad. Eso nos llevara a trabajar con ms de un predicado para la misma relacin, que era el problema original. (Por ms que se llamen igual, si la cantidad de parmetros es distinta, es otro predicado, ya que no hay forma de consultarlos a la vez).Errores comunesRepito lgica por hacer mal uso de polimorfismoSupongamos que tenemos la siguiente base de conocimiento:juguete(ingenio(cuboRubik,10)).juguete(ingenio(encajar,2)).juguete(munieco(50)).juguete(peluche(300)).juguete(peluche(150)).Suponiendo que quiero saber si un juguete es caro, lo que sucede cuando su precio supera los 100 pesos.Se sabe que el precio de los juguetes de ingenio es de $20 por cada punto de dificultad, el precio del mueco es el indicado, y el precio de los peluches es la mitad de su tamao en mm.Una forma de resolverlo sera:esCaro(ingenio(_,Dificultad)):- 100 &lt; Dificultad * 20.esCaro(munieco(Precio)):- Precio &gt; 100.esCaro(peluche(Tamanio)):- Tamanio / 2 &gt; 100.El problema es que repito la lgica de cundo un juguete es caro en las tres clusulas, porque me falta abstraer la lgica del precio.Si tengo la lgica del precio delegada en otro predicado, luego no necesito repetir la lgica de esCaro en cada clusula:esCaro(Juguete):- precio(Juguete,Precio), Precio &gt; 100. precio(ingenio(_,Dificultad), Precio):- Precio is Dificultad * 20.precio(munieco(Precio),Precio).precio(peluche(Tamanio),Precio):- Precio is Tamanio / 2.Intento poner una variable en el nombre del functorSupongamos que tenemos un predicado que relaciona una patente con un vehculo, como la siguiente base de conocimiento:vehiculo(opp564, camion(mercedes,2014)).vehiculo(agt445, auto(504,1995)).vehiculo(mmr444, camion(scania,2010)).Y quisiramos saber las patentes de los autos anteriores al 2000. Lo siguiente es incorrecto:patenteDeAutoInteresante(Patente):- vehiculo(Patente, Tipo(_,Anio)), Anio &lt; 2000.Por qu es incorrecto? Primero, Prolog no me deja usar el nombre del functor como un dato, que yo pueda poner en una variable operar. Adems, lo siguiente no sera posible:vehiculo(ppt666, moto(2010)). % No respeta la aridadvehiculo(ert434, lancha(2017,yamaha)). % El orden es otrovehiculo(dfg345, karting(rojo)). % Y puede ser que no incluya la informacin del ao y haya que hacer otra cosa!Por lo tanto, lo que deberamos hacer es obtener el dato de ao de alguna otra maneraRelaciones que repiten lgica una forma podra ser relacionando el ao con la patente:patenteDeAutoInteresante(Patente):- anioPatente(Patente, Anio), Anio &lt; 2000.El problema est en que estamos obligados a relacionar la patente con el vehculo para saber el ao, repetida en cada clusula de anioPatente/2:anioPatente(Patente, Anio):- vehiculo(Patente, moto(Anio)).anioPatente(Patente, Anio):- vehiculo(Patente, camion(_, Anio)). anioPatente(Patente, Anio):- vehiculo(Patente, lancha(Anio, _)).El problema est en que estamos relacionando la patente con un ao, cuando eso depende del vehculo.Una posible solucinLa siguiente solucin arregla todos los problemas mencionados arriba:patenteDeAutoInteresante(Patente):- vehiculo(Patente,Vehiculo), anioVehiculo(Vehiculo,Anio), Anio &lt; 2000. anioVehiculo(camion(_,Anio),Anio).anioVehiculo(auto(_,Anio),Anio).anioVehiculo(moto(Anio),Anio).anioVehiculo(lancha(Anio,_),Anio).anioVehiculo(karting(Color),Anio):- colorDelAnio(Color,Anio).colorDelAnio(rojo,2010).colorDelAnio(verde,1990).colorDelAnio(azul,2015).De esta forma se evita repetir lgica creando relaciones acordes a los datos de los individuos, aprovechando el polimorfismo en patenteDeAutoInteresante/1 al unificar toda la estructura con Vehiculo (sin iportar su forma) y recin haciendo pattern matching cuando es necesario, en anioVehiculo/2.As puedo meter los functores con la forma que yo quiera , y an as mi predicado patenteDeAutoInteresante/1 no cambia. Esa es la gran ventaja del polimorfismo. Lo nico que tengo que hacer es definir el predicado anioVehiculo/2 para ese nuevo tipo de functor, y ya todo anda ;)" + +} , + +{ + +"title" : "Polimorfismo parametrico y ad hoc", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/polimorfismo-parametrico-y-ad-hoc.html", +"date" : "", +"content" : "Primero que nada, cuando hablamos de polimorfismo nos referimos a la capacidad de una funcin de recibir por parmetro valores de distinto tipo. No es taaan importante esta clasificacin en s, pero lo explicamos para despejar dudas.Cuando hablamos de polimorfismo paramtrico tenemos una sola definicin de la funcin, en cambio cuando tenemos polimorfismo ad-hoc tenemos muchas definiciones para la misma funcin de modo que se puedan soportar distintos tipos. Lo que normalmente hacemos (al menos en paradigmas) es definir funciones que son polimrficas paramtricamente, sin embargo s usamos mucho funciones con polimorfismo ad-hoc.Tpicas funciones con polimorfismo paramtrico son las que operan sobre listas: filter, map, all, any, length, foldl, etc. No necesariamente pueden recibir cualquier valor, depende de lo que hagas. Por ejemplo el tipo de length es[a]-&gt;Int,con lo cual puede recibir una lista de cualquier cosa, pero el de sum esNuma=&gt;[a]-&gt;aentonces slo puede recibir una lista numrica (igual es polimrfica, porque hay muchos tipos de nmeros, ver Typeclass Num).La suma tambin es una operacin polimrfica y su tipo es:Numa=&gt;a-&gt;a-&gt;aSi te fijas bien no hay forma de diferenciarlos por el tipo, lo que cambia es que la suma est definida de forma diferente para cada tipo numrico (si se animan pueden buscarlo en el Prelude de Haskell), mientras que el sum tiene una nica definicin.Se puede ver que en ambos ejemplos de polimorfismo paramtrico una sola definicin de la funcin sirve para todos los casos polimrficos, eso se da porque: - En el caso de length porque no hace nada especfico con los elementos de la lista, entonces pueden ser cualquier cosa. - En el caso de sum porque se basa en la suma (+) que a su vez es una operacin polimrfica.Y esto ltimo tambin me parece interesante, una funcin paramtricamente polimrfica muchas veces se basa en otra que usa polimorfismo ad-hoc (no es la nica forma pero es algo frecuente). por qu es interesante esto?Bueno primero hay que ver, quin saca ventaja del polimorfismo? Y si lo penss, las funciones que usan polimorfismo ad-hoc no sacan gran ventaja del polimorfismo, si yo tengo que definir la suma para cada tipo numrico es lo mismo que hubiera hecho sin polimorfismo.El chiste es justamente que luego alguien basndose en eso puede hacer funciones que sirvan para todos los nmeros, porque la suma sirve para todos los nmeros. La suma (+) labura para el sum.Eso es equivalente a lo que pasa en objetos cuando decimos que dos objetos son polimrficos para un tercero, quin saca ventaja? El tercero! - Que las golondrinas y los picaflores sean polimrficos a la hora de volar o comer no les da ventajas a las aves (ni a volar o comer), si no a los terceros que pueden hacerlos volar y comer indistintamente. - Que la suma funcione polimrficamente para reales y enteros no beneficia a la suma, sino a otras funciones que pueden sumarlos indistintamente.En fin volviendo a lo que deca al principio, insisto en que lo importante no es qu tipo de polimorfismo usa una funcin o cul es la definicin de polimorfismo ad-hoc sino, para qu sirve, qu ventajas le da a mi programa, cmo se puede aprovechar el potencial del polimorfismo para hacer cdigo ms claro/extensible/robusto/ponga aqu su cualidad preferida." + +} , + +{ + +"title" : "Polimorfismo", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/polimorfismo.html", +"date" : "", +"content" : " Polimorfismo paramtrico y ad-hoc Polimorfismo en el Paradigma Lgico Polimorfismo en el Paradigma de Objetos" + +} , + +{ + +"title" : "Portal del investigador", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/portal-del-investigador.html", +"date" : "", +"content" : " Escribiendo un paper Lectura de un paper Academic Phrase Bank Website compendio de frases comunes para escritura de ndole acadmica." + +} , + +{ + +"title" : "Possibly incorrect indentation or mismatched brackets", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/possibly-incorrect-indentation-or-mismatched-brackets.html", +"date" : "", +"content" : "El problemaUn error muy comn en Haskell, tanto para los que recin arrancan como para los ms experimentados, es pifiarla con los enters, espacios o tabs. Por qu? Haskell no usa llaves {} ni bloques do-end para delimitar secciones del cdigo, sino que se basa en el uso de caracteres blancos (withespaces) para darse cuenta, por ejemplo, cuando termina una ecuacin de una funcin.Entonces, si ponemos tabs, espacios, enters de menos o de ms, obtendremos un slo error:parseerror:possiblyincorrectindentationormismatchedbracketsLo que significa: che, revis tus withespaces; mientras tanto no voy a intentar interpretar a tu cdigoLa solucinLa solucin al problema depende de dnde hayas pifiado. Veamos algunos casos comunes:Dejar espacios o tabs antes de la cabecera de la funcinLa cabecera de la funcin debe arrancar justo contra el margen.Mal:fx=x+1Bien:fx=1Poner enters de ms entre dos ecuaciones de la misma funcinLas ecuaciones de una funcin deben estar siempre juntas, sin enters de ms entre ellasMal:f0=0fx=x+1Bien:f0=0fx=x+1Poner enters de ms en una expresin largaA veces puede pasar que por un tema de legibilidad queremos partir escribir una sola expresion larga a lo largo de varias lineas (aunque en general, el problema ah es que la expresin es larga por falta de delegacin). El tema es que tenemos que ser muy claros en indicarle a Haskell que la expresin no termin.Dos reglas: Si hacemos eso, en general vamos a tener que poner la expresin entre parntesis Y todo caso, debemos respetar la identacinMal:fx=maxx1Mal:fx=(maxx1)Mal:fx=(maxx1)Bien (multiples lneas)fx=(maxx1)Bien (una sola lnea)fx=maxx1" + +} , + +{ + +"title" : "Precedencia de los operadores mas comunes en haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/precedencia-de-los-operadores-mas-comunes-en-haskell.html", +"date" : "", +"content" : "Definicin en el PreludeLa siguiente tabla muestra la precedencia de los operadores que ms utilizamos en Haskell. A mayor nmero mayor precedencia. Por ejemplo, el operador + tiene mayor precedencia que &lt;, por lo tanto si escribimos:3&lt;4+5se entiende como:3&lt;(4+5)La tabla (simplificada) es la siguiente:-- Primero vienen las funciones prefijas (como even, map, etc.) y luego los chirimbolos:infixr9.infixl9!!infixr8^,^^,**infixl7*,/,`quot`,`rem`,`div`,`mod`,:,%infixl6+,-infixr5:infixr5++infix4==,/=,&lt;,&lt;=,&gt;=,&gt;,`elem`,`notElem`infixr3&amp;&amp;infixr2||infixr0 $Eso significa que el signo pesos (la funcin $) tiene muy poca precedencia, va a ser la ltima en considerarse. Y por el contrario las funciones prefijas (como el even o el abs) van a tener mucha precedencia. Entonces esta cuenta:abs 3 - 5 -- Se lee como "le resto 5 al valor absoluto de 3"Debe leerse como le resto 5 al valor absoluto de 3, porque eso es lo que significa en Haskell, porque la aplicacin prefija de abs tiene ms precedencia que el -. El resultado de esa cuenta es (-2) (negativo).Lo mismo sucede ac:4 &gt; 2 * 3 -- Se lee como "quiero saber si el 4 es mayor a la multiplicacin entre 2 y 3"Se lee as porque el &gt; tiene menos precedencia que el *, entonces el * se hace primeroPor ltimo, para romper la precedencia se usan parntesis. Si yo quiero decir el valor absoluto de la resta entre 3 y 5 lo que debo hacer es:abs (3 - 5) -- Se lee como "el valor absoluto de la resta entre 3 y 5"Uso del signo pesos ($) para evitar parntesisVer Uso del signo pesos en Haskell para ver cmo se aprovecha que el $ tenga tan poca precedencia.Bonus: AsociatividadLas palabras clave infixl e infixr permiten indicar la asociatividad del operador. Los operadores definidos con infixl asocian a izquierda, mientras que los infixr asocian a derecha. Por lo tanto, la expresin:3+4+5Se evala como:(3+4)+5Ya que el operador asocia a izquierda. En cambio la expresin:2:3:4:[]Se debe leer como:2:(3:(4:[]))Ya que el operador asocia a derecha, al igual que la composicin (.), por ejemplo:snd.head.filterevenDebe leerse como:snd.(head.filtereven)Tambin puede notarse que todos los operadores tienen menor precedencia que la aplicacin funcional, es decir que al ejemplo anterior podramos definirlo completamente si agregamos los parntesis alrededor de .:snd.(head.(filtereven))Los operadores definidos como infix no son asociativos, por ejemplo el operador de igualdad ==. Por lo tanto la expresin:a==b==cNo se entiende como (a == b) == c ni como a == (b == c); la expresin sin parntesis es incorrecta." + +} , + +{ + +"title" : "Precedencia de mensajes", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/precedencia-de-mensajes.html", +"date" : "", +"content" : "Muchas veces nos encontramos en la situacin de querer mandar varios mensajes en una misma sentencia, donde hay varios objetos involucrados. Qu mensaje se evala primero? Cul ser el objeto que finalmente sea pasado como parmetro?sto se ve con varios ejemplos:2+3squared.Cmo lo interpreto? (2+3) al cuadrado? 2 + (3 al cuadrado)?Otro ejemplo:3+2*4Cmo lo interpreto? (3+2) * 4? 3 + (2*4)?PrecedenciaBueno, antes de saber cmo evaluarlo, hay que recordar que existen 3 tipos de mensajes en Smalltalk: Unarios: pepita energa Binarios: 3 + 2 De Palabra Clave: pepita come: 20.As, de arriba para abajo, es la precedencia de los mensajes. Ms arriba en la lista est el mensaje, ms fuerza tiene para atraer al objeto que tiene al lado.Y qu sucede si hay dos mensajes con igual precedencia? Se evala de izquierda a derecha.El ejemplo finalLa siguiente evaluacin:2raisedTo:5-2*4sqrt.Devuelve 64 se evala 4 sqrt (da 2), luego 5 - 2 (da 3), luego 3 * 2 (da 6) luego 2 raisedTo: 6S, no hay precedencia de operadores como estamos acostumbrados, con lo cual el - tiene la misma precedencia que el * ya que ambos son binarios.Y si yo quiero que primero se haga la multiplicacin?Uso parntesis, como en cualquier otro lenguaje:2raisedTo:5-(2*4sqrt).As se restara el resultado de multiplicar 2 por la raz de 4 al 5, con lo cual estaramos elevando 2 a la 1." + +} , + +{ + +"title" : "Preguntas frecuentes del paradigma logico", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/preguntas-frecuentes-del-paradigma-logico.html", +"date" : "", +"content" : "Agregar elementos a una listaPreguntaRespuestaAcordate de que el paradigma lgico no tiene efectos colaterales, por lo tanto agregar un elemento a una lista no es algo que se pueda hacerS puedo relacionar una lista con otra que tenga un elemento ms:X=[Head|Tail]Va a unificar Head con la cabeza de X y Tail con la cola. Por lo tanto X tendr un elemento ms que Tail (que sera Head). Eso se puede usar tanto para conseguir una lista X con un elemento ms que Tail como para obtener un Tail con un elemento X.Lo que nunca podras hacer es:X=[Head|X](Ntese que en los ejemplos se utiliza el igual de una forma que en un predicado probablemente no sera necesario. Casi casi casi siempre el igual est de ms.)" + +} , + +{ + +"title" : "Preguntas frecuentes", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/preguntas-frecuentes.html", +"date" : "", +"content" : "Problemas con el entornoEstoy tratando de pasar algunas clases del tp de objetos y no puedo crear clases.#* Fijate que el nombre de la clase este en maysculas.Interpretacin de erroresEvalu mi cdigo, me tir un error y no s lo que significa#* Dont panic#* Le el ttulo de la ventana de error#* Si con eso no alcanza para entender, lee la cadena de mensajes que se fueron enviando (stacktrace). Cada lnea del stacktrace dice:#**la clase del objeto receptor, si el receptor era una clase dice adems class, por ejemplo Golondrina class#**entre parntesis la clase en donde est definido el mtodo que se ejecut#**el mensaje enviado a ese objeto#*Si todava no sabs qu fue, apret Debug que te aporta mucha ms informacin para entender qu pasMensajes ms comunes:MessageNotUnderstoodProblema: Se mand un mensaje que el receptor no entiende.Posibles soluciones: Revisar que el objeto receptor fuera correcto (si es nil probablemente haya algo sin inicializar) Revisar que no haya error de tipeo (el mensaje coincide con el nombre del mtodo definido) Revisar que el mtodo est definido en el lugar correcto (del lado de las instancias si es un mtodo de instancia y del lado de la clase si el receptor es una clase)Un caso particular con el que se pueden encontrar es que un objeto de una clase de ustedes no entienda el mensaje #adaptToNumber:andSend:, lo cual puede surgir si como parmetro de una operacin matemtica no era un nmero (por ejemplo 3 + pepita).NonBooleanReceiver: proceed for truthProblema: Se le mand a un objeto que no es booleano un mensaje de booleanos como ifTrue:ifFalse:Solucin: Mirar el stacktrace, en algn momento va a aparecer: ClaseDelObjetoReceptor(Object)&gt;&gt;mustBeBoolean ms abajo en el stacktrace debera aparecer un mensaje que definieron ustedes o DoIt si se envi desde el workspace. Darle doble click a ese mensaje para abrir el debugger y ver qu pas.***Error: This block accepts arguments, but was called with arguments***Problema: se evalu un bloque con una cantidad de argumentos distinta de la esperada.Solucin: Buscar en el stacktrace el mtodo que definieron (o DoIt si fue directo desde el workspace) que evalu el bloque con una cantidad incorrecta de parmetros." + +} , + +{ + +"title" : "Preparacion de un entorno de desarrollo groovy", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/preparacion-de-un-entorno-de-desarrollo-groovy.html", +"date" : "", +"content" : "Download e instalacin base Vas a la pgina https://github.com/groovy/groovy-eclipse y buscs el link de update que se adapte a la versin de tu Eclipse En Help &gt; Install New Software geners un nuevo update site en base al link del punto anterior Componentes a instalar: Extra Groovy Compilers, eleg la versin ms reciente Groovy-Eclipse m2e Configurator for Groovy-Eclipse Y luego lo instals (va a tardar un ratito)Ojo, no te confes en usar el Eclipse Marketplace porque trae versiones anteriores del plugin.Luego hay que instalar el plugin de Maven, ahora s desde el Eclipse Marketplace. Help &gt; Eclipse Marketplace, buscs Maven, seleccions Maven Integration for Eclipse, Install, ConfirmUtilizar Groovy en otro IDE Segu este link: http://groovy-lang.org/ides.htmlDocumentacin http://groovy-lang.org/documentation.htmlLinks de inters Pgina principal de Groovy Groovy vs Scala" + +} , + +{ + +"title" : "Preparacion de un entorno de desarrollo java 8", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/preparacion-de-un-entorno-de-desarrollo-java-8.html", +"date" : "", +"content" : " REDIRECT Preparacin de un entorno de desarrollo Java" + +} , + +{ + +"title" : "Preparacion de un entorno de desarrollo java", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/preparacion-de-un-entorno-de-desarrollo-java.html", +"date" : "", +"content" : "IntroduccinPara realizar aplicaciones de complejidad mediana-grande en Java, es recomendable contar con un entorno de trabajo que contemple al menos: Una herramienta de versionado de fuentes Una herramienta de manejo de dependencias Un mecanismo para automatizar los procesos administrativos del desarrollo (test, release, deploy, etc) Un entorno de programacin que permita: Ayudas a la deteccin temprana de errores, autocomplecin, herramientas para navegar y buscar gilmente dentro del cdigo, etc. Soporte para la realizacin de refactors automatizados Integracin con la mayor cantidad posible de las dems herramientas que utilizamos. En este artculo se propone una configuracin de entorno de trabajo que intenta cumplir con los anteriores objetivos. Las herramientas seleccionadas para eso son: Java Development Kit Eclipse como entorno integrado de desarrollo Git como repositorio de fuentes y herramienta de versionado Maven como herramienta para manejar dependencias y automatizar diversos procesos administrativos.Adicionalmente se instalarn extensiones al entorno de desarrollo eclipse para integrarlo con git y maven.JDK (Java Development Kit)Contiene un compilador y una mquina virtual (el runtime) que traduce a cdigo de mquina el cdigo intermedio que genera el compilador (.java COMPILADOR (javac.exe) .class VM (java.exe) ejecutable final).Al tiempo de escribir este artculo la ltima versin estable es 1.8. Para el propsito aqu descripto es recomendable instalar la Standard Edition.Download e instalacin baseA continuacin se detallan los pasos bsicos de instalacin segn el sistema operativo que se est utilizando. Luego de realizar este paso inicial se deber pasar a la configuracin del entorno.Este es el link de downloads.Desde ah buscan el Latest Release y se descargan el JDK del sistema operativo que est instalado en sus mquinas.Para ms detalles adicionales a los que se encuentran en esta pgina, se puede consultar el manual de instalacin de sun.UbuntuPara instalarlo en Ubuntu se puede hacer:$ sudo apt-get install openjdk-8-jdkPara definir la versin por defecto, pods correr$ sudo update-alternatives --config javay definir la versin con la que vas a usar.Otros sistemas operativosPara otros sistemas operativos desde este link segus la explicacin paso por paso que se encuentra aqu.Documentacin Java Tutorials Javadoc reference guide Writing comment tipsEclipseLa instalacin del eclipse es muy sencilla: hay que bajar el que corresponda a su sistema operativo desde http://www.eclipse.org/downloads/ y descomprimirlo en su disco rgido. Posiblemente deseen crear un acceso directo para apuntar al ejecutable.A los efectos de los objetivos planteados en este artculo, se recomienda elegir la versin denominada Eclipse IDE for Java EE Developers.Esa versin pesa bastante. Si no van a utilizar las herramientas de programacin web es posible utilizar la versin ms liviana Eclipse IDE for Java Developers.Configuraciones adicionales Te recomendamos chequear estas configuraciones de EclipseDocumentacin Pgina principal de EclipseMavenPara instalar Maven te recomendamos seguir las instrucciones de esta pginaCreacin de un proyecto bsicoUna vez instaladas todas las herramientas, se puede crear un proyecto en esta plataforma siguiendo este tutorial (ojo, este es un tutorial bsico, si necesitan usar otras tecnologas de presentacin busquen los tutoriales en las pginas de las tecnologas correspondientes).Mavenizar un proyecto existenteSi ya arrancaste tu proyecto y decidiste ms tarde que necesitabas usar Maven, pods mavenizarlo de alguna de las siguientes maneras.Usando M2Eclipse Click derecho en el Proyecto Configure -&gt; Convert to Maven Project Ingresar el groupId deseado. Preferentemente que sea el package name que se hayan definido antes, ej: org.uqbar.arena.exampes FinishIndependientemente de si su proyecto respeta la estructura estndar de un proyecto Maven, lo van a tener configurado y funcionando. De hecho, si crean los directorios y mueven el paquete a src/main/java, Maven automgicamente lo va a detectar..srcmainjavaorguqbararenaexamplesMain.javaresourcespom.xml Probamos hacer una compilacin e instalacin local.Links tiles Amigandonos con el entorno de desarrollo" + +} , + +{ + +"title" : "Preparacion de un entorno de desarrollo scala", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/preparacion-de-un-entorno-de-desarrollo-scala.html", +"date" : "", +"content" : "Download e instalacin baseHay varios IDEs para desarrollar con Scala, incluso podemos desarrollar sin un IDE (solamente necesitamos el compilador). De todos modos ac vamos a explicar cmo se puede armar un ambiente de desarrollo usando Eclipse y Maven (para manejo de dependencias). La opcin ms recomendada es trabajar con IntelliJCreacin de un proyecto Maven con ScalaLa configuracin de un proyecto Scala para poder utilizar Maven es relativamente compleja y tiene varias sutilezas, principalmente para poder integrar ambas herramientas dentro del Eclipse. Por eso, recomendamos la utilizacin de este parent project que creamos con este objetivo especfico:&lt;parent&gt;&lt;groupId&gt;org.uqbar-project&lt;/groupId&gt; &lt;artifactId&gt;uqbar-scala-parent&lt;/artifactId&gt; &lt;version&gt;1.3&lt;/version&gt; &lt;/parent&gt;Para poder utilizar ese parent project necesario realizar previamente realizar las tareas indicadas en Configuracin de Maven para poder utilizar las herramientas de UqbarEste parent project realiza varias configuraciones: Agrega las dependencias con Scala y ScalaTest Define src/main/scala como directorio default donde estn los fuentes (y src/test/scala donde estn los tests). Le indica al maven que utilice el compilador de Scala. Configura la integracin con el Eclipse.Documentacin Documentacin oficial Manuales de referencia Scala by Example escrito por Martin Odersky, el creador de Scala. Effective ScalaLinks de inters Pgina principal de Scala Un tutorial de Scala de Javi Fernndes, miembro de Uqbar" + +} , + +{ + +"title" : "Problemas comunes con los tipos numericos de haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/problemas-comunes-con-los-tipos-numericos-de-haskell.html", +"date" : "", +"content" : "Para salir del pasoAl programar en Haskell suele pasar que muy frecuentemente tenemos problemas con los tipos numricos, en particular suele ocurrir al intentar hacer divisiones. Por ejemplo en el siguiente programa, la funcin promediopromedioxs=sumxs/lengthxsProduce el siguiente error: Could not deduce (Fractional Int) arising from a use of / from the context: Foldable t bound by the inferred type of promedio :: Foldable t =&gt; t Int -&gt; Int at main.hs:1:1-32 In the expression: sum xs / length xs In an equation for promedio: promedio xs = sum xs / length xsEl problema surge porque el Haskell tiene diferentes tipos de valores numricos (enteros, reales, etc): un sistema de tipos muy estricto que hace que no sea sencillo mezclar los distintos tipos de valores en una misma operacin.La versin corta es que length xs es un entero y la operacin / no est definida para los nmeros enteros.Solucin en GHCiEs necesario convertir el resultado de length xs al tipo de datos adecuado, utilizando la funcin fromIntegral:divisionxs=sumxs/fromIntegral(lengthxs)Esto funciona siempre que yo quiera hacer una divisin no-entera y uno de los parmetros (o ambos) es un entero. Para hacer divisiones enteras tenemos las funciones div y mod.Solucin si utilizs pdepreludat con stackEs necesario convertir el resultado de length xs al tipo de datos adecuado, utilizando la funcin toFloat:divisionxs=sumxs/fromIntegral(lengthxs)La historia completaLa divisin no est definida para los enteros?Para comprender la totalidad del problema, es necesario comprender el tipo de la funcin (/):Main&gt;:t(/)(/)::Fractionala=&gt;a-&gt;a-&gt;aSe puede ver que (/) es una funcin polimrfica, es decir que puede ser utilizada con diferentes tipos de datos. Sin embargo no puede ser utilizada con cualquier tipo de dato; la restriccin es que el tipo tiene que ser instancia de la clase Fractional. En particular, los tipos enteros de Haskell (Int e Integer) no son instancias de Fractional, por lo tanto siempre que se tenga un valor de alguno de esos tipos deber ser convertido utilizando la funcin fromIntegral.Con esa idea en mente, analizamos los tipos de las funciones del ejemplo de la seccin anterior:Main&gt;:tsumsum::Numa=&gt;[a]-&gt;aMain&gt;:tlengthlength::[b]-&gt;IntY podemos concluir que sum no tendr problemas, porque funciona para cualquier tipo numrico (por definicin todas las instancias de Fractional son instancias de Num.En cambio la funcin length no es polimrfica en cuanto a su valor de retorno; aunque puede recibir cualquier tipo de lista, siempre devuelve un Int. Entonces el resultado de length no puede ser parmetro de (/).Algunos casos ms complicadosSupongamos que no utilizamos la funcin sum, y en cambio queremos definir la nuestra propia, de la siguiente manera:suma=foldr(+)0O bien (para no definir una que ya existe), podemos definirprod=foldr(*)1Funcionan las siguientes definiciones?div2xs=sumaxs/fromIntegral(lengthxs)flocaxs=prodxs/fromIntegral(lengthxs)Si intentamos hacer eso, obtendremos el siguiente error:ERROR`[`file:.&#92;pruebas.hs:15`](file:.&#92;pruebas.hs:15)`-InstanceofFractionalIntegerrequiredfordefinitionofdiv2Para entender por qu se produce esto, debemos analizar nuevamente los tipos de suma y prod:Hugs&gt;:tsumasuma::[Integer]-&gt;IntegerMain&gt;:tprodprod::[Integer]-&gt;IntegerY como se puede ver devuelven valores de tipo Integer que, como dijimos antes, no es instancia de Fractional y por lo tanto no funciona.La idea de la seccin anterior tambin puede servir en este caso (aunque no es la nica forma):div2xs=fromIntegral(sumaxs)/fromIntegral(lengthxs)flocaxs=fromIntegral(prodxs)/fromIntegral(lengthxs)Aprovechando mejor el polimorfismoEn realidad hay una forma mejor de solucionar el problema planteado en la seccin. La desventaja de la solucin descripta consiste en que, al resolverlo de esa manera, la funcin suma slo funciona para valores de tipo Integer; lo que puede resultar muy restrictivo en un futuro.Por qu sucede esto? Como sabemos, Haskell trabaja con inferencia de tipos, por lo tanto, cuando nosotros no indicamos en nuestro programa de qu tipo son los valores que espera y devuelve una funcin, el sistema intentar descubrir ese tipo por nosotros. Normalmente este mecanismo de inferencia es suficiente y resulta de gran utilidad, ya que nos permite tener un lenguaje fuertemente tipado que nos ayuda a encontrar muchos errores en nuestro cdigo en una fase previa a la ejecucin del programa, al mismo tiempo que nos evita de la burocracia y el engorro de tener que indicar el tipo de cada funcin explcitamente.Sin embargo en este caso el tipo inferido por el sistema de tipos de Haskell es subptimo. El tipo inferido es [Integer] -&gt; Integer, es decir, que slo funciona para listas de tipo Integer.Sin embargo, si miramos la definicin de suma, podemos ver que se basa en las funciones foldr y (+), cuyos tipos son:Main&gt;:tfoldrfoldr::(a-&gt;b-&gt;b)-&gt;b-&gt;[a]-&gt;bMain&gt;:t(+)(+)::Numa=&gt;a-&gt;a-&gt;aEs decir que no hay ningn motivo para restringir el tipo a [Integer] -&gt; Integer, dado que foldr funciona para cualquier tipo de lista y (+) funciona para todos los tipos de la familia Num (es decir, todos los tipos numricos predefinidos del Haskell). De hecho, si consultamos el tipo de la expresin foldr (+) 0, obtenemos:Main&gt;:tfoldr(+)0foldr(+)0::Numa=&gt;[a]-&gt;aque es el tipo que buscamos.Lamentablemente, cuando intenta inferir un tipo automticamente para la funcin suma, Haskell le asigna un tipo monomrfico, defaulteando en el tipo Integer. La forma de evitar esta restriccin es haciendo explcita nuestra intencin de que la funcin suma sea polmrfica, esto se logra asociando a la funcin una indicacin del tipo esperado.El tipo esperado no es otro que el de la expresin foldr (+) 0, es decir, Num a =&gt; [a] -&gt; a. La definicin de la funcin quedara as:suma::Numa=&gt;[a]-&gt;asuma=foldr(+)0Al hacer ese cambio la siguiente definicin pasa a estar correctamente tipada:-- con GHCidiv2xs=sumaxs/fromIntegral(lengthxs) -- con pdepreludat y stack ghcidiv2xs=sumaxs/toFloat(lengthxs) " + +} , + +{ + +"title" : "Prototipado vs clases", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/prototipado-vs-clases.html", +"date" : "", +"content" : "En el paradigma orientado a objetos, cuando se suscita el problema de que existan diferentes objetos con igual comportamiento pero diferente identidad y estado interno, podemos abordarlo de diferentes formas. Dos esquemas muy usados son el de clases y el que se basa en prototipos. Cada lenguaje (o herramienta) suele implementar una sla de stas opciones, aunque existen variaciones. Los lenguajes ms tradicionales (como Java, Smalltalk, y C#) usan el esquema de clases y herencia, y en otros lugares (como Javascript, en el Object Browser para Smalltalk), se usa el esquema de prototipado.Ms all de cul de estos esquemas usemos, la base es la misma: objetos que se mandan mensajes en un ambiente aprovechando las ideas de encapsulamiento, delegacin y polimorfismo.La idea de este artculo es ver cmo se puede trabajar en cada esquema para solucionar los mismos problemas.Compartir comportamiento entre varios objetosQu pasa si pepita no es la nica golondrina que nos interesa tener en nuestro programa?. Tambin estn josefa y pepona que comen y vuelan como pepita y tambin deben tener una energa que podamos monitorear. Estara bueno que josefa y pepona puedan tener el mismo comportamiento que pepita sin tener que definir lo mismo 3 veces. Aqu es donde entran los conceptos de clase y de prototipo, dependiendo de las herramientas que tengamos disponibles.Cuando existe la idea de clase en nuestra implementacin del paradigma, el comportamiento se define una sola vez en la clase y tanto pepita como josefa y pepona pasan a ser instancias de esta clase. No podemos slo tener a pepita con su propio cdigo porque todos los objetos son instancias de una clase que las define. Cuando cualquiera de las golondrinas reciba el mensaje vola:, lo van a entender y buscarn el mtodo que lo define en la clase Golondrina.Si no tenemos la idea de clase, el mecanismo que necesitamos para que josefa y pepona compartan el cdigo con pepita es la colonacin. Clonando a pepita podemos crear un nuevo objeto (josefa) que entiende los mismos mensajes y tiene sus mismas variables, y adems conoce a pepita como su prototipo.Si queremos cambiar el comportamiento general de las golondrinas alcanza con realizar estos cambios sobre la clase Golondrina o sobre el prototipo pepita. Al decir que un objeto es clon de otro estamos estableciendo una relacin tan fuerte entre ellos como al decir que un objeto es instancia de una clase al trabajar en el otro esquema.Diferenciar el comportamiento de algunos objetosSupongamos que pepona es otro clon de pepita. Queremos que pepona (que es una golondrina perezosa) entienda el mensaje descansar, que hace subir su energa en 50 joules. Sin embargo pepita y josefa que son golondrinas normales deberan seguir teniendo el mismo comportamiento (no entenderan descansar).En el esquema de prototipado podemos simplemente modificar a pepona como lo haramos con cualquier otro objeto, sin importar si fue clonado a partir de pepita o no.#pepona&gt;&gt;descansarenergia:=energia+50Cuando mandemos el mensaje pepona descansar lo va a entender (ya que tiene un mtodo propio para este mensaje), va a ejecutar su mtodo descansar y su energa se incrementar. Si mandramos pepita descansar tendramos un error porque pepita no entendera ese mensaje.Qu pasara si estuviramos trabajando con el esquema de clases? Siempre que aparece comportamiento nuevo, necesitamos crear otra clase que lo incluya, con lo cual necesitaramos crear una clase GolondrinaPerezosa que herede de Golondrina y definir all el mtodo #descansar. De esta forma, pepona ya no debera ser una instancia de Golondrina sino de GolondrinaPerezosa.pepona:=GolondrinaPerezosanew.peponadescansar."estovaafuncionar"pepita:=Golondrinanew.pepitadescansar."pepitanovaaentenderelmensajedescansar"Si lo que queremos es agregar algn atributo nuevo para pepona, estaramos en la misma situacin, habra que agregarlo en el objeto #pepona o en la clase GolondrinaPerezosa respectivamente.Redefinir comportamientoSiguiendo con pepona, la golondrina perezosa, sabemos que cuando vuela gasta ms energa para despegar (15 en vez de 10). Una primer solucin podra ser redefinir el mtodo vola:#pepona/#GolondrinaPerezosa&gt;&gt;vola:unosKilometrosenergia:=energia-(unosKilometros*5+15)Cuando le mandemos el mensaje pepona vola: 10, buscar una definicin propia (o en su clase) para vola: y al encontrarla ejecutar ese mtodo. Haber agregado este mtodo no cambia el comportamiento de pepita y josefa, que es lo que queramos.Sin embargo podramos dar un paso ms para evitar la repeticin de cdigo, siendo que lo nico que cambia es el valor de la energa para despegar. Una solucin mejor sera:#pepita/#Golondrina&gt;&gt;vola:unosKilometrosenergia:=energia-(unosKilometros*5+selfenergiaParaDespegar)&gt;&gt;energiaParaDespegar^10#pepona/#GolondrinaPerezosa&gt;&gt;energiaParaDespegar^15Ahora, cuando le mandemos el mensaje pepona vola: 10, buscar una definicin propia (o en su clase) para vola:, no la va a encontrar, con lo cual seguir buscando en su prototipo (o la superclase de su clase) donde s existe. Al ejecutar esa definicin, se enviar a s misma el mensaje #energiaParaDespegar; empieza a buscar un mtodo con ese nombre en s misma (o en su clase GolondrinaPerezosa), lo encuentra y retorna 15, valor que se usar para completar la ejecucin de vola:Si le mandamos el mensaje pepita vola: 10, encontrar y ejecutar la definicin en s misma (o en su clase Golondrina) al igual que para el mensaje #energiaParaDespegar que retornar el valor 10.Conclusin / Corolarios Al solucionar el problema utilizando abstracciones ya existentes, prototipado es conceptualmente ms sencillo Entonces, el mecanismo de clases agrega una abstraccin, ya no tengo slo objetos comunes. Adems, prototipado me resuelve el problema de redefinicin sin ms conceptos, en cambio en clases yo tengo que agregar la idea de herencia entre las clases para lograr algo parecido. Por otro lado, la separacin objeto - clase viene asociada con un mecanismo para conocer a las clases globalmente, mientras que si uso prototipado tengo que preocuparme por guardar el prototipo de mis objetos en algn lado Si bien en prototipado se puede usar a prototype para delegar, esto no es lo mismo que usar super al usar herencia, ya que prototype referencia a otro objeto (con su propio estado) mientras que super referencia al mismo objeto que recibi el mensaje inicial En prototipado, el contenedor de comportamiento es dinmico, es un objeto ms de mi sistema. Al usar clases, en muchos lenguajes la separacin clase - objeto es tal que pertenecen a dos mundos diferentes, el esttico y el dinmico." + +} , + +{ + +"title" : "Prototipado", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/prototipado.html", +"date" : "", +"content" : "Un prototipo segn la RAE es un Ejemplar original o primer molde en que se fabrica una figura u otra cosa. Este trmino se utiliza en la programacin orientada a objetos para aquellos objetos que sirven como base para obtener otros objetos como l, la forma de obtener nuevos objetos a partir del prototipo se denomina clonacin.Qu problema es el que resuelve la clonacin, entonces?Si ya existe un objeto con un determinado comportamiento y estado interno y lo clonamos, obtendremos otro objeto con el mismo comportamiento (entiende los mismos mensajes y se definen de la misma forma) y estado interno (comparte la forma, pero cada objeto tiene sus propias referencias, ya que queremos que el estado de cada objeto sea independiente) que el original.Qu significa sto? Que si queremos que todas las golondrinas del universo coman y vuelen de la misma forma (pero que cada una tenga su propia energa), entonces podemos hacer que todas sean clones de pepita, nuestra golondrina original, la que usaremos como prototipo.La principal diferencia entre clonar un objeto y crear otro copiando el cdigo que ya tenamos es que el cdigo no est duplicado. Al decir que un objeto es clon de otro estamos estableciendo una relacin fuerte entre ellos; si se agrega, quita o modifica algn mtodo en el prototipo, todos sus clones se vern afectados por este cambio, lo cual lgicamente no sucede si duplicamos cdigo, tendramos que hacer los cambios en cada lugar que est repetido pudiendo olvidar hacer alguno o cometer errores fcilmente. Lo mismo suceder si le agregamos o quitamos alguna referencia al prototipo, el mismo cambio se har sobre sus clones. Donde apunte la referencia en cada clon ser probablemente diferente.Volviendo sobre el ejemplo de pepita la golondrina, supongamos que queremos clonarla para crear otra golondrina, josefa.Si tenamos el siguiente cdigo en el objeto pepita:#pepita&gt;&gt;vola:unosKilometros"Gasta5joulesporkilmetroms10dedespegue"energia:=energia-(unosKilometros*5+10)Y le mandamos a josefajosefavola:10.El objeto josefa buscar la implementacin de vola: en s mismo inicialmente, y al no tener una definicin propia, la seguir buscando en su prototipo que es pepita. All encuentra una definicin y la ejecuta. La energa que va a disminuir es la de josefa, el estado interno de pepita se va a mantener intacto.Tambin podramos tener una definicin de vola: usando mensajes a self en vez de accediendo directamente a la variable energa:#pepita&gt;&gt;vola:unosKilometrosselfenergia:selfenergia-(unosKilometros*5+10)Como self siempre es el objeto receptor del mensaje, si vola: se lo mandamos a josefa, self estar referenciando a josefa, no a pepita.Lgicamente, si le mandamos vola: a pepita, va a entender el mensaje, a ejecutar su propia definicin de vola: y modificar su propia energia sin afectar a ninguno de sus clones.Una vez que tenemos el objeto clonado podemos trabajar con l modificando su comportamiento y su estado interno, con lo cual podremos mantener las similitudes con su prototipo en aquellos puntos en los cuales nos interese e introducir diferencias en otros. Si el prototipo define un mtodo para el mensaje #msj1 y el clon cambia su implementacin, el prototipo no se ver afectado por este cambio y el clon usar su propia implementacin cuando reciba #msj1 en vez de usar la del prototipo.A modo resumen podemos decir que el method lookup al usar prototipado se resuelve de la siguiente forma:Tenemos el objeto o1 cuyo prototipo es o2, y o1 recibe el mensaje #m o1 tiene un mtodo cuyo nombre es #m, se ejecuta ese mtodo. o1 no tiene un mtodo cuyo nombre es #m, entonces busca una definicin en su prototipo o2 tiene un mtodo cuyo nombre es #m, se ejecuta ese mtodo (el receptor sigue siendo o1) o2 no tiene un mtodo cuyo nombre es #m, con lo cual habr un error porque o1 no entiende el mensaje #m Si o2 a su vez tuviera otro prototipo, el method lookup continuara hasta que se llegue a un objeto que no es clon de ningn otro.Para descargar la herramienta que soporta prototipado en Pharo Smalltalk y tutoriales de uso: Object Browser (LOOP)Ejemplo completoNota: El ejemplo de Pepita es obra de Carlos Lombardi. Cualquier reproduccin del mismo deber ser autorizada por el autor." + +} , + +{ + +"title" : "Pseudovariable", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/pseudovariable.html", +"date" : "", +"content" : "Una pseudovariable es un variable manejada por el ambiente, dicha variable no puede ser asignada a otro valor.En Smalltalk las 2 pseudovariables ms usadas son self y superEn Wollok contamos solo con self (en realidad existe super, pero no como pseudovariable, si no como una palabra reservada, con un significado especial)." + +} , + +{ + +"title" : "Publicar un proyecto en svn", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/publicar-un-proyecto-en-svn.html", +"date" : "", +"content" : "Antes de publicar un proyecto es (obviamente) necesario tener un usuario y un repositorio svn, una forma de hacer eso es Crear un proyecto en xp-devDesde el Eclipse:Botn derecho sobre el proyecto -&gt; Team -&gt; Share Project y ah poner la url del repositorio donde esta el proyeto seguido de . Por ejemplo:http://svn2.xp-dev.com/svn/nombre_del_repositorio/nombre_del_proyecto/trunkEsto va a crear la carpeta del proyecto y/o trunk si no existen.Este paso nos lleva a la perspectiva Synchronize del eclipse donde tenemos que comitear para guardar en el trunk nuestros sources del proyecto. En este momento, antes de comitear tenemos que indicarle al svn los archivos y carpetas que no queremos versionar, para esto, le damos botn derecho -&gt; Add to .Lo que tenemos que agregar al en un proyecto simple es: la carpeta que guarda informacin del eclipse la carpeta que es donde estan los compilados el y el**Recordemos que siempre ponemos en el todo aquello que se genera automticamente, en este caso, todos estos archivos los genera el maven.**Entonces ahora que ya le dijimos al svn que es lo que no queremos versionar, estamos en condiciones de comitear. Botn derecho sobre el proyecto -&gt; Commit.Despus hay que crear las carpetas branches y tags en el repositorio.Desde la consola:" + +} , + +{ + +"title" : "Python", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/python.html", +"date" : "", +"content" : "Sobre el lenguaje: Python Programming Language Official Site Python (Wikipedia)Herramientas basadas en Python: Django Pylons/Pyramid Tornado Twisted (usado por ejemplo, por Dropbox) Sage GIMP Paint Shop Pro LightWave 3D Raspberry Pi" + +} , + +{ + +"title" : "que entendemos por programacion orientada a objetos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/que-entendemos-por-programacion-orientada-a-objetos-.html", +"date" : "", +"content" : "Hay muchas visiones sobre lo que significa orientado a objetos, que llevan a mltiples discusiones. En esta pgina hay una definicin posible http://wcook.blogspot.com.ar/2012/07/proposal-for-simplified-modern.html" + +} , + +{ + +"title" : "Instalacion de ReactJS", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/react-instalacion.html", +"date" : "", +"content" : "Pasos previosSi ya estuviste trabajando con Angular estos pasos no son necesarios, pero conviene verificar que ya estn instalados. Si ests en entorno Windows te recomendamos instalarte Git Bash Seguimos con NodeJS, preferentemente la ltima versin (tiene que ser 20.4.0 superior). Luego NPM (Node Package Manager), con el que vamos a hacer los builds de nuestras aplicaciones. El editor de texto que vamos a soportar en la cursada es Visual Studio Code (hay una versin portable si ests en una mquina sin privilegios de administrador).Especficos de ReactPlugins Visual Studio CodeDentro de Visual Studio Code, las extensiones que recomendamos para trabajar con React deberan ser las mismas con las que trabajaste en Angular y adems revisar que tengas: ESLint - Microsoft Prettier - ESLint - Rebecca Vest y adems Vitest - Zixuan ChenCrear un proyecto React de ceroPara crear un proyecto React desde la consola Git Bash o bien desde una terminal Linux escribimos:npm create vite@latest nombre-del-proyectoY luego Select a framework: React: seleccionar React como framework de UI Select a variant: Javascript + SWC: elegir la variante Javascript con SWC (herramienta de reemplazo de Babel)Tambin pods usar el template directo React + Javascript + SWC (eso evita que tengas que seleccionar el tipo de proyecto):npm create vite@latest nombre-de-proyecto -- --template react-swcPor defecto la aplicacin cliente levantar en el puerto 5173. Como suele quedarse levantada aun cuando canceles la lnea de comando y el navegador, te dejamos este link que te dice cmo bajar el proceso del sistema operativo para correr otro ejemplo.Configuraciones adicionales para Algoritmos IIIUna vez creado el proyecto, te recomendamos que agregues estas configuraciones.Agregar dependenciasAgregamos estas dependencias de Prettier y Vitest (el framework de testing)npm i @testing-library/react @testing-library/jest-dom @testing-library/user-event @vitest/coverage-v8 @vitejs/plugin-react jsdom prettier vitest -DArchivo .nvmrcTener un archivo .nvmrc es conveniente si todo el equipo trabaja con NVM (el versionador de Node). El contenido especifica qu versin de Node vamos a utilizar:20.4.0Archivos tilesEn la carpeta raz cre los siguientes archivos .markdownlint.json (configuracin del Linter para archivos con extensin .md), con el siguiente contenido{ "MD013": false, "MD024": false, "MD025": false} .prettierrc (configuracin de Prettier para eliminar puntos y coma, definir tab de 2 espacios, utilizar single quote, etc.) Es importante que tod@s tengan esta configuracin para que no haya un montn de conflictos en git a la hora de pushear.{ "trailingComma": "all", "tabWidth": 2, "semi": false, "singleQuote": true}Linter para javascriptEl archivo .eslintrc.cjs debe tener la siguiente configuracin:module.exports = { root: true, env: { browser: true, es2020: true }, extends: [ 'eslint:recommended', 'plugin:react/recommended', 'plugin:react/jsx-runtime', 'plugin:react-hooks/recommended', ], ignorePatterns: ['dist', '.eslintrc.cjs'], parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, settings: { react: { version: '18.2' } }, plugins: ['react-refresh'], rules: { 'semi': ['error', 'never'], 'prefer-const': [ 'warn', { 'destructuring': 'any', 'ignoreReadBeforeAssign': false } ], 'getter-return': ['error'], 'no-async-promise-executor': ['warn'], 'no-cond-assign': ['warn', 'except-parens'], 'no-dupe-keys': ['error'], 'no-empty': ['warn'], 'no-ex-assign': ['error'], 'no-extra-boolean-cast': [ 'error', { 'enforceForLogicalOperands': true } ], 'no-extra-parens': ['warn', 'all'], 'no-func-assign': ['error'], 'no-import-assign': ['error'], 'no-inner-declarations': ['error', 'both'], 'no-obj-calls': ['error'], 'no-promise-executor-return': ['error'], 'no-sparse-arrays': ['error'], 'no-template-curly-in-string': ['error'], 'no-unreachable': ['error'], 'no-unreachable-loop': ['error'], 'no-unsafe-optional-chaining': ['error'], 'require-atomic-updates': ['error'], 'use-isnan': ['error'], 'block-scoped-var': ['error'], 'consistent-return': ['error'], 'default-param-last': ['warn'], 'no-alert': ['error'], 'no-caller': ['error'], 'no-constructor-return': ['error'], 'no-global-assign': ['error'], 'no-lone-blocks': ['warn'], 'no-multi-spaces': ['warn'], 'no-new': ['warn'], 'no-param-reassign': ['error'], 'no-proto': ['warn'], 'no-redeclare': ['error'], 'no-return-assign': ['error'], 'no-return-await': ['warn'], 'no-self-assign': ['error'], 'no-sequences': ['warn'], 'no-useless-catch': ['warn'], 'no-useless-return': ['error'], 'no-void': ['error'], 'no-with': ['error'], 'no-undef': ['off'], 'react/display-name': ['off'], 'react/jsx-uses-react': 'off', 'react/react-in-jsx-scope': 'off', 'react-refresh/only-export-components': [ 'warn', { allowConstantExport: true }, ], },}Configuracin del proyectoAl archivo package.json le modificamos el script lint y le agregamos test y coverage (borrale los comentarios porque no estn permitidos en json): "scripts": { "lint": "eslint --cache --fix .", // modificar ... // agregar "test": "vitest", "coverage": "vitest run --coverage" },.gitignoreAl archivo .gitignore se le pueden incorporar estas lneas:# VSC - Git Lens.historyArchivo de configuracin para Visual Studio CodeTe recomendamos que dentro del proyecto crees una carpeta .vscode y dentro un archivo settings.json que tenga este contenido:{ "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "editor.formatOnSave": true, "files.autoSave": "onFocusChange" }Configuracin para el testeo unitario de frontendHay que definir un archivo setupTests.js en el raz de nuestro proyecto, que tenga el siguiente contenido:import "@testing-library/jest-dom/vitest"El archivo vite.config.js contiene la configuracin que necesitamos para ejecutar los tests, es importante agregar un reporter de tipo json-summary para que el build de Github Actions cree el badge con el % de cobertura automticamente:/// &lt;reference types="vitest" /&gt;/// &lt;reference types="vite/client" /&gt;import { defineConfig } from 'vite'import react from '@vitejs/plugin-react'// https://vitejs.dev/config/export default defineConfig({ plugins: [react()], resolve: { alias: { src: '/src', components: '/src/components', }, }, test: { globals: true, setupFiles: ['./setupTests.js'], // es importante definirlo en un archivo aparte para que se ejecute en otro contexto environment: 'jsdom', coverage: { reporter: ['text', 'json', 'html', 'json-summary'], }, }}) Si no configurs el archivo setupTests.js te va a aparecer un mensaje de error: Error: Invalid Chai property: toBeInTheDocument en cada expect.Por otra parte, los imports conviene hacerlos en forma absoluta, desde src para las definiciones de dominio, services, etc. y src/components para los componentes de React.Archivo jsconfig.jsonIncorporemos este archivo que nos ayudar para que el plugin auto-import funcione, as como definiciones extra para el intrprete JS:{ "compilerOptions": { "baseUrl": ".", "checkJs": false, "jsx": "react-jsx", "paths": { "src/*": [ "./src/*" ], "components/*": [ "./src/components/*" ] } }}Nuestra recomendacin es que no actives el chequeo de tipos de javascript (para eso es preferible usar typescript). Si lo activs mediante la opcin: ... "checkJs": true, ...en el archivo jsconfig.json, tens que agregar esta configuracin al archivo vite.config.js: coverage: { // agregar provider: 'v8', // reporter: ['text', 'json', 'html', 'json-summary'], },Ejemplo de un archivo para Github ActionsTe dejamos este archivo de ejemplo que tens que guardar en .github/workflows/build.yml. No hay que hacer ningn cambio.Cmo configurar los badges en tu README Para agregar el badge del build de Github Actions, segu estas instrucciones Para agregar el badge del porcentaje de cobertura, tens que agregar la imagen que genera el mismo build de Github Actions (tal cual est escrito): ![coverage](./badges/coverage/coverage.svg)Links relacionados Temario Algoritmos III" + +} , + +{ + +"title" : "Recursividad en haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/recursividad-en-haskell.html", +"date" : "", +"content" : "Una funcin recursiva es aquella que en su definicin se invoca a s misma. La misma por lo general cuenta con una definicin recursiva y al menos un caso base que corta la recursividad.Recursividad sin listas Un ejemplo clsico de recursividad es [http://es.wikipedia.org/wiki/Sucesi%C3%B3n_de_Fibonacci Fibonacci]. fibonacci0=0fibonacci1=1fibonaccin=fibonacci(n-1)+fibonacci(n-2)Esta funcin tiene dos casos base para el 0 y el 1 (ya que la definicin recursiva requiere el resultado para los dos nmeros anteriores, no alcanza con un solo caso base) y para todos los otros nmeros una definicin recursiva genrica.Es necesario definir primero los casos base, ya que la variable n es un patrn demasiado genrico, tanto el 0 como el 1 matchean con la variable n, por ende deben definirse antes los casos para el 0 y para el 1 para que sean encontrados primero por el motor de Haskell.Para pensar: qu pasa si la consulta realizada esfibonacci(-1)Dado que la tercer definicin admite nmeros negativos va a entrar en un loop infinito. Como no es correcto usar fibonacci con nmeros negativos, podramos mejorar nuestra definicin restringiendo el dominio de la funcin usando guardas de esta forma:fibonacci0=0fibonacci1=1fibonaccin|n&gt;=2=fibonacci(n-1)+fibonacci(n-2)Ahora el resultado de aplicar fibonacci con un nmero negativo sera un error ya que no hay ninguna definicin vlida para el valor indicado :)Recursividad con listasSiendo las listas estructuras recursivas (compuestas por una cabeza y una cola que a su vez es una lista) la forma ms natural para trabajar con ellas es recursivamente. La lista [1,2,3] puede tambin escribirse como 1:2:3:[] (donde el : es la funcin usada para armar listas y puede ser usada convenientemente para pattern matching)Un ejemplo fcil es el length.length[]=0length(x:xs)=1+lengthxsVeamos ahora la funcin reverse.reverse [] = []reverse (x:xs) = reverse xs ++ [x]Usamos el patrn de lista vaca [] para el caso base, ya que la segunda definicin indefectiblemente nos llevar a ella, y el patrn de cabeza y cola para poder avanzar de a un paso por la estructura y poder procesarla fcilmente. En estos casos en particular no importa el orden de las definiciones, ya que la lista con al menos un elemento no matchea con la lista vaca y viceversa.Loops infinitosAnalicemos la siguiente funcin:muchosDen=n:(muchosDen)Si consultamos en el intrprete&gt;muchosDe5Esta funcin no podra terminar nunca, ya que no hay ningn punto en el que se corte la recursividad. Sin embargo, lo que s podramos hacer con esta funcin es usarla en un contexto que acote la ejecucin gracias a la evaluacin perezosa. Veamos el siguiente ejemplo:&gt;(sum.take10.muchosDe)550" + +} , + +{ + +"title" : "Recursividad en logico", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/recursividad-en-logico.html", +"date" : "", +"content" : "Un predicado recursivo es aquel que en alguna de sus clusulas se invoca a s mismo. Los predicados recursivos para poder funcionar correctamente necesitan contar con algn caso base que corte la recursividad.Recursividad Sin ListasUn primer ejemplo es el predicado ancestro/2 que relaciona a una persona con otra si la primera cumple con ser su padre o ser ancestro de su padre. Teniendo un predicado padre(Padre, Hijo) podemos hacer:ancestro(Ancestro, Descendiente):- padre(Ancestro, Descendiente). ancestro(Ancestro, Descendiente):- padre(Padre, Descendiente), ancestro(Ancestro, Padre).Ac se ve que ancestro/2 tiene dos clusulas: una que se invoca al mismo predicado ancestro/2 y otra que no. No importa cul de las dos definamos primero, porque Prolog va a intentar ambas de todos modos. Lo que s es importante de la clusula recursiva es que demos un pasito que nos acerque al caso base antes de hacer la consulta recursiva, en este caso es preguntar quin es ancestro del padre de la persona que nos interesaba en primer lugar.Algo que puede parecer complejo es analizar la inversibilidad de este predicado. Teniendo en cuenta que el predicado padre/2 es inversible, el caso base es inversible, pero qu pasa con el caso recursivo? Las variable Descendiente se va a ligar gracias a padre/2, y la variable Ancestro aparece por primera vez al consultar el mismo predicado que estamos definiendo Bueno, gracias a que el caso base es inversible, podemos confiar que eventualmente se va a ligar, por ende ancestro/2 se hace inversible a s mismo.Una cosa interesante para pensar en este ejemplo es que el predicado ancestro/2 define una relacin que cumple con la propiedad transitiva. Recordando un poco la teora detrs de esto: Una relacin R es transitiva si: a R b y b R c =&gt; se cumple a R c.Otro ejemplo tpico de predicado recursivo es factorial/2, que relaciona a un nmero con su factorial sabiendo que para el 0 es 1 y para los otros nmeros es el factorial del nmero anterior multiplicado por s mismo. Una primer aproximacin en base a esto podra ser:factorial(0,1).factorial(N,F):- AnteriorisN-1, factorial(Anterior,F2), FisF2*N.Esta definicin parece que resuelve el problema, pero no hay que olvidarse que en el paradigma lgico la bsqueda de soluciones es exhaustiva. Si consultamos por el factorial de 1, la primer respuesta ser 1 ya que el factorial de 0 es 1, y 1 * 1 da 1. Pero siendo que 0 tambin matchea con la variable N entrar en un loop infinito al segundo intento. Por ese motivo, una definicin correcta sera:factorial(0,1).factorial(N,F):-N&gt;0,AnteriorisN-1,factorial(Anterior,F2),FisF2*N.De esa forma, ambos casos son excluyentes entre s y el 0 slo puede tener como respuesta al 1.Y la inversibilidad? Algo que salta a la vista es que para consultar el factorial del anterior necesitamos calcular el anterior, y tambin necesitamos validar que N &gt; 0, y eso impone restricciones porque los predicados (&gt;)/2 e is/2 necesitan que N est ligada con un valor concreto. O sea que esta consulta no va a funcionar: factorial(N, 6).Analicemos la inversibilidad para la segunda aridad. Esta otra consulta: factorial(3, Factorial). funcionara?La variable F aparece recin al final, a la izquierda del is, con lo cual no habra problema por ese lado.De hecho, si no fuera inversible para la segunda aridad la consulta recursiva no se podra resolver tampoco, porque se est usando una variable F2 que no tiene chances de estar ligada previamente como para que sea una consulta individual. Al igual que para el primer ejemplo, esa consulta recursiva funciona gracias a que tiende al caso base que es inversible.Recursividad Con ListasLas listas son indiviuos compuestos cuya naturaleza es recursiva, por ese motivo la recursividad es una forma comn para trabajar con ellas. La clave para hacer un ejercicio, si ste se resuelve con recursividad, es poder pensar recursivamente. sto significa que cuando digan, por ejemplo una sumatoria se define como.. ah, en la definicin, tienen que usar el concepto de sumatoria de nuevo, para definirla. Cmo? Y, separando el problema, por ejemplo, en cabeza y cola. Y ese es el chiste, juntando esas dos cosas y pensando un poquito, pueden hacer recursividad sobre listas.SumatoriaLa cola de una sumatoria qu tiene que ver con la sumatoria de la lista entera? Y, la sumatoria de la cola es casi todo el problema resuelto, slo le falta agregar un detallito que implica trabajar con el elemento que tenemos disponible:sumatoria([Cabeza|Cola],S):-sumatoria(Cola,SCola),%Estoyaescasitodoelproblemaresuelto!Solofaltasumarlacabeza:SisSCola+Cabeza.Y por supuesto que necesitamos un caso base. El caso base se piensa generalmente por exclusin. Qu caso no consider arriba? La lista vaca. (En ste caso)sumatoria([],0).UltimoA ver, el ltimo de una lista Es el mismo ltimo de la cola!:ultimo([Cabeza|Cola],Ultimo):-ultimo(Cola,Ultimo).Caso base, una lista con un elemento (la lista vaca no tiene ltimo, sera esperable que una consulta para la lista vaca de falso):ultimo([E],E).Completito:ultimo([_|Cola],Ultimo):-ultimo(Cola,Ultimo).ultimo([E],E).Todos menos el ltimoAhora, el principio de la lista (todos menos el ltimo). ste es loquito, porque podemos partir ambas listas, as:principio([Cabeza|Cola],[Cabeza|PrincipioDeLaCola]):-Y claro, porque la cabeza es la misma en la lista original que en su principio. Pero hay que relacionar Cola y PrincipioDeLaCola..principio([Cabeza|Cola],[Cabeza|PrincipioDeLaCola]):-principio(Cola,PrincipioDeLaCola).principio([E],[]).ReverseEntonces, pensemos otro problema: dar vuelta una lista. Es un poco ms interesante: Necesitamos poner el ltimo adelante, y la cola de la lista dada vuelta es el principio de la lista al revs:reverse(ListaOriginal,[Ultimo|PrincipioAlReves]):-Uf, pero hay que ver de dnde sale eso! Y, la llamada recursiva la conocemos:reverse(PrincipioDeLaLista,PrincipioAlReves),Y listo, ahora hay que poner antes y despus de esa condicin cosas para que ligue las variables correspondientes; Ligamos PrincipioDeLaLista, antes de la llamada recursiva:reverse(ListaOriginal,[Ultimo|PrincipioAlReves]):-principio(ListaOriginal,PrincipioDeLaLista),reverse(PrincipioDeLaLista,PrincipioAlReves), ...Y ahora nos falta saber de dnde sacamos el ltimo:reverse(ListaOriginal,[Ultimo|PrincipioAlReves]):-principio(ListaOriginal,PrincipioDeLaLista),reverse(PrincipioDeLaLista,PrincipioAlReves),ultimo(ListaOriginal,Ultimo).Les dejo el caso base a ustedes.Ejercicio: SubconjuntoCmo se hace el subconjunto de una lista? (sin permutaciones)As tiene que funcionar:`?-subconjunto([1,2,3],Sub).`Sub=[];Sub=[2];Sub=[2,3];Sub=[3];Sub=[1];Sub=[1,2];Sub=[1,2,3];Sub=[1,3];false.Pista: El subconjunto puede pensarse con dos casos recursivos ms el caso base." + +} , + +{ + +"title" : "Redefinicion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/redefinicion.html", +"date" : "", +"content" : "La redefinicin se produce cuando una clase vuelve a definir, o sea redefine, alguno de los mtodos heredados de su superclase. El nuevo mtodo sustituye al heredado para todos los objetos de la clase que lo ha redefinido, de manera que sus objetos tienen un comportamiento modificado respecto de los objetos de la superclase.As, la redefinicin permite que al definir una nueva clase sus objetos no slo extiendan o amplen el funcionamiento de los objetos de la superclase, sino tambin los modifiquen, ajustndolo a los requerimientos y necesidades especficas para los cuales se cre la subclase.La redifinicin se puede usar para definir la misma operacin que antes pero con alguna variante (ac mayormente se usa super) o para definir la misma operacin sin cdigo en comn con el heredado (es una redefinicin sin super, se puede ver un ejemplo en Prototipado vs Clases#Redefinir comportamiento)." + +} , + +{ + +"title" : "Refactoring", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/refactoring.html", +"date" : "", +"content" : "This article is a stub!Links Artculo de Kent Beck que habla sobre [Ideas para ordenar nuestros refactorings](dont-cross-the-beams}) Artculo de Javier Fernandes con un ejemplo prctico de refactoring Un artculo de Ward Cunningham The Debt Metaphor. Creo que Cunningham es una de las personas que mejor entiende lo que significa programar. La tesis de William Opdyke" + +} , + +{ + +"title" : "Reflection", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/reflection.html", +"date" : "", +"content" : "Es un caso particular de metaprogramacin, donde metaprogramamos en el mismo lenguaje en que estn escritos (o vamos a escribir) los programas. Es decir, todo desde el mismo lenguaje.Nota de color: Inicialmente el lenguaje pionero en cuanto a reflection fue LISP.El ejemplo ms visible de esto es el caso de smalltalk, donde no existe una diferenciacin entre IDE y nuestro programa. Ambos estan hechos en smalltalk, y de hecho viven en un mismo ambiente. Ambos estan construidos con objetos y pueden interactuar entre s.De hecho, muchos componentes del IDE Pharo son elementos de metaprogramacin, y utilizan reflection para inspeccionar nuestras clases y objetos.Tipos de reflectionPara esto, generalmente, es necesario contar con facilidades o herramientas especficas, digamos soporte del lenguaje. Entonces reflection, adems, abarca los siguientes items que vamos a mencionar en esta lista: Introspection: se refiere a la capacidad de un sistema, de analizarse a s mismo. Algo as como la introspeccin humana, pero en trminos de programa. Para eso, el lenguaje debe proveer ciertas herramientas, que le permitan al mismo programa, ver o reflejar cada uno de sus componentes. Self-Modification: es la capacidad de un programa de modificarse a s mismo. Nuevamente esto requiere cierto soporte del lenguaje. Y las limitaciones van a depender de este soporte. Intercession: es la capacidad de modificar la semntica del modelo que estamos manipulando, desde el mismo lenguaje.Un MOP (MetaObject Protocol) es un framework de objetos que describe o modela un sistema de objetos. MOP sera el trmino correcto para lo que en java llamamos API de reflection. En realidad el API de reflection de java es un caso de MOP.Dependiendo de la implementacin y del lenguaje, el MOP puede soportar o no los tipos de reflection que enumeramos arriba: introspection, self-modification &amp; intercession.IntrospectionSe refiere a poder obtener informacin acerca de los elementos de nuestro programa: clases, fields, mtodos, funciones, predicados (en otros paradigmas).La capacidad de introspection es la ms comn en los MOPs. Digamos que es la ms simple de implementar, comparndolas con los otros tipos de reflection.Veamos algunas herramientas que nos dan los lenguajes Java y Smalltalk (Pharo):Informacin esttica:Paraobtenerlaclasedeunobjeto:enJava:getClassenPharo:classEnlaclaseclassestnlosmtodos:enJava:getMethods,getDeclaredMethods,getFields,getConstructors,getMethod,getSuperclassenPharo:instVariables,methodDictionary,superclassInformacin dinmica:Obtenerelvalordeunfield:enJava:unField.get(unObjeto)enPharo:unObjetoinstVarNamed:fieldNameSetearelvalordeunfield:enJava:unField.set(unObjeto,unValor)enPharo:unObjetoinstVarNamed:fieldNameput:unValorInvocarunmtodo:enJava:unMethod.invoke(unObjeto,parametro1,parametro2,...)enPharo:unObjetoperform:#selectorwithArguments:listaDeParametrosCrearunainstancia:enJava:unConstructor.invoke(parametro1,parametro2,...)ounaClase.newInstance()enPharo:unaClasenewSelf-modificationSupongamos que queremos hacer el refactor extract superclass, para esto vamos a usar self-modification en Pharo, donde modificar el metamodelo usando el mismo lenguaje es algo cotidiano por ejemplo, para crear una clase usamos el template que nos provee el System Browser:Objectsubclass:#NameOfSubclassinstanceVariableNames:''classVariableNames:''poolDictionaries:''category:''.que no es ms que un mensaje que se le manda a la clase Object.Lo que hacemos es, dada una clase, crear una super clase a partir de ella, dicindole el nombre de le nueva clase, las variables de instancia que quiero que tenga, los mtodos que quiero que tenga. As es como nos gustara poder usarlo:SimpleExtractSuperclassRefactoringextractSuperclass:#GuerrerowithInstanceVariables:SoldadoinstVarNamesandMethods:(Soldadoselectorsdifference:#(pasofuerza))fromClass:Soldado.El resultado de esta prueba debera ser crear una clase Guerrero, a partir de otra clase Soldado ya existente. Guerrero va a ser superclase de Soldado y va a tener todas las variables de instancia que tiene Soldado (le podramos especificar cules variables de instancia queremos ponerle, pero por simplicidad, le pasamos todas). Tambin vamos a mover todos los mtodos de Soldado, excepto paso y fuerza.Por supuesto, nuestro refactor debe ser independiente del dominio de los guerreros. Nuestro metaprograma sera bsicamente (obviando accessors):#SimpleExtractSuperclassRefactoringclass&gt;&gt;extractSuperclass:newSuperClassNamewithInstanceVariables:instanceVariableNamesandMethods:selectorsToMovefromClass:aClassselfnewtarget:aClass;superClassName:newSuperClassName;instanceVariableNames:instanceVariableNames;selectors:selectorsToMove;execute.#SimpleExtractSuperclassRefactoring&gt;&gt;executeselfcreateSuperClass.selfmoveInstanceVariables.selfmoveMethods.&gt;&gt;createSuperClassselftargetSuperClass:(selftargetsuperclasssubclass:selfsuperClassNameinstanceVariableNames:''classVariableNames:''poolDictionaries:''category:selftargetcategory).selftargetSuperClasssubclass:selftargetnameinstanceVariableNames:selftargetinstanceVariablesStringclassVariableNames:selftargetclassVariablesStringpoolDictionaries:''"Ahoranonosimporta,perohabraquecopiarlotambinparaquenosepierda"category:selftargetcategory.&gt;&gt;moveInstanceVariablesselfinstanceVariableNamesdo:[:instVarName|selftargetremoveInstVarNamed:instVarName.selftargetSuperClassaddInstVarNamed:instVarName.]&gt;&gt;moveMethodsselfselectorsdo:[:selector|selftargetSuperClasscompile:(selftarget&gt;&gt;selector)getSource.selftargetremoveSelector:selector.]Algunos mtodos de self-modification que usamos: Agregar un mtodo: unaClase compile: cdigo del mtodo Borrar un mtodo: unaClase removeSelector: #selector Agregar una variable de instancia: unaClase addInstVarNamed: nombre de la variable y para borrarla: unaClase removeInstVarNamed: nombre de la variable" + +} , + +{ + +"title" : "Relleno caprese", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/relleno-caprese.html", +"date" : "", +"content" : "Cantidad: 1 docena y mediaIngredientes: 150 gramos de Jamon 235 gramos de Muzzarella (el paquete de La Serenisima) Medio paquete de Albahaca Un tomate bien grande. Slo un poquito de sal al tomate + albahaca" + +} , + +{ + +"title" : "Relleno dale", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/relleno-dale.html", +"date" : "", +"content" : "Cantidad: 1 docena y mediaIngredientes: 125 gramos de jamon 235 gramos de queso, 80% fontina y un toque de Muzzarella 3 cebollas chicas 1 cebolla de verdeo. 1 morrn (medio verde y medio rojo) un puado de aceitunas, ponele 8 a 10. 2 huevos duros Condimentos, un caldito de verdura, aceite, sal, pimienta y condimento para pizza, todo en el preparado de cebolla + morrn." + +} , + +{ + +"title" : "Relleno de carne", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/relleno-de-carne.html", +"date" : "", +"content" : "Cantidad: 2 docenas y mediaIngredientes: 1kg de carne 1kg de cebollas 4 huevos duro 2 cebolla de verdeo 1 morrn rojo 1 morrn verde Un poquito de salsa de tomate CominoExtras: Aceitunas, 10 Medio Chorizo" + +} , + +{ + +"title" : "Representacion de informacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/representacion-de-informacion.html", +"date" : "", +"content" : " Cul_es_la_diferencia_entre_una_tupla_y_una_lista?" + +} , + +{ + +"title" : "Resolver problemas de dependencias maven dentro de eclipse", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/resolver-problemas-de-dependencias-maven-dentro-de-eclipse.html", +"date" : "", +"content" : "Cuando el plugin de maven dentro de eclipse no puede resolver una dependencia puede ser por varios motivos, aqu tratamos de armar una lista de cosas para revisar.Est mal el settings.xmlNormalmente si estuviera mal el settings entonces debera quejarse por no encontrar el parent project y no esos, pero si no le pusiste parent a tu pom entonces podra mostrar ese error. Por otro lado si tens algn otro ejemplo de la ctedra que te anda, eso querra decir que el settings est bien.Dentro del eclipse se configura donde est el settings.xml en Windows / Preferences -&gt; Maven / User Settings. En principio ese debera ser el settings.xml que hay que modificar para agregarle el repo maven de uqbar.Est mal el pom.xmlSi tens mal las versiones no te va a andar. Asegurate de copiar exactamente lo que dice algn pom de ejemplo.Est mal nuestro server creo que no es el caso, pero nunca hay que descartar esa opcin.Est mal la conexin a Internet.Asegurate de tener Internet y que el maven/eclipse tengan acceso a ella, revisar firewalls, proxies etc.Est mal tu repo localEsto es ms probable de lo que podra pensarse, si todo lo anterior falla lo ms lgico es que sea esto. Suele pasar cuando uno usa maven desde una conexin mala (como la de frba), intenta bajar un jar, no lo logra y se mambea: queda registrado como que no se pudo bajar y no vuelve a intentar.Para resolver esto hay que ir al repo local y borrar la info de cache una forma fcil es borrar todo el directorio uqbar, pero si miran a dentro pueden ser ms sutiles.Est mal el eclipseEl eclipse tambin tiene sus cachs y no es raro que se mambeen ac no hay soluciones elegantes, darle clean al proyecto, clean al maven, restartearl el eclipse y todas esas cosas desagradables.En algn caso yo lo resolv haciendo un touch del archivo .classpathBorrar parte del repo local tambin obliga al eclipse a refrescar sus cachs.Mi proyecto no es de tipo maven / No tengo el men maven en mi proyectoVisualmente se puede ver si un proyecto es de tipo maven en el cono del proyecto. Este debera tener una m en el mismo.Para convertirlo a proyecto maven hay que apretar click derecho sobre el proyecto y luego Configure / Convert to Maven Project" + +} , + +{ + +"title" : "Responsiveness", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/responsiveness.html", +"date" : "", +"content" : "Aplicaciones responsiveHacer que una aplicacin sea responsive implica optimizar el contenido y la interaccin de la interfaz de usuario en base al tamao y resolucin de la pantalla.Esto se relaciona con el concepto de usabilidad: el contenido debe adaptarse para pantallas ms chicas (celulares, en modo vertical o apaisado), medianas (tablets) o grandes (monitores de 25), a veces implica reordenar los controles, a veces sacar los elementos que pueden llegar a molestar la experiencia de usuario.Algunos frameworks de presentacin web que trabajan sobre esta idea son: Twitter Bootstrap Material Design Foundation Skeletonentre otros.Manualmente, el css permite especificar estilos condicionales mediante el uso de media queries. Pods ver un ejemplo que discrimina css para desktops, tablets, telfonos grandes y pequeos.Links relacionados Temario Algoritmos III" + +} , + +{ + +"title" : "Resumen de wicket pros y contras", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/resumen-de-wicket--pros-y-contras.html", +"date" : "", +"content" : "Resumen general Tema Cmo lo resuelve Wicket Widgets Si bien dependen de lo que HTML ofrece, del lado del servidor se puede trabajar con componentes visuales que rendericen tablas paginadas, combos anidados, etc. Layout Al igual que en Web, el layout no est reificado en objetos del lado del servidor sino que se define en el html (y opcionalmente en el css). Binding Se mapea cada componente con su modelo correspondiente (esttico o dinmico). El CompoundPropertyModel trabaja por convencin y permite bajar la cantidad de lneas de configuracin. Manejo de estado La pgina tiene estado como cualquier objeto que pertenece al ambiente Java. Navegacin Se pueden generar nuevas instancias de una pgina o recibir una pgina como parmetro. Al abrir nuevas sesiones desde el browser se generan nuevas instancias de pgina automticamente. La navegacin es a nivel aplicacin y no a nivel hipervnculo de documento. Pasaje de informacin entre pginas Puedo definir constructores para las pginas, pasando como parmetro toda la informacin que necesite (incluyendo la pgina padre). Manejo de eventos Los botones deben definirse como submit y no como button para que pueda funcionar el binding de atributos, por las restricciones de la tecnologa web: slo con submit los parmetros viajan al servidor. Los buttons como los links definen sus listeners, el mapeo es sencillo: no hay que escribir tres servlets distintos para comprar, reservar o dar de baja la reserva, ni escribir un servlet que en el doGet/doPost tenga un switch gigante. Highligths Stateful Model manejo automtico de estado en sesin no requiere conocer scopes: session, request, etc. Modelo de componentes al estilo SWT soporta extensiones trabajando con tcnicas OO conocidas Transparencia en la comunicacin con el server Al igual que en cliente pesado, los mtodos onClick() son invocados automticamente por el framework Html markup muy poco intrusivo Slo hay que anotar el tag con el id del componente. Ej: Aceptar Al trabajar con un html de prueba, eso permite la separacin de tareas entre el diseador y el programador (el diseador no sufre si hay problemas de performance o cambio en los datos porque el html contiene un prototipo de ejemplo en s mismo) Problemas Sigue atado al concepto de formulario Si bien el form es un objeto con las ventajas que eso trae, el desarrollador tiene que pensar en el submiteo del form. Muy fuerte vnculo entre markup y modelo componentes java. Hace rgida y burocrtica la vista. Modelo de componentes orientado a la jerarqua Hay que subclasear TODO! (botones, links, etc.) Trabaja poco con composicin Una vez que el programador se hizo amigo de la tecnologa, se imponen refactors para evitar escribir muchas lneas de cdigo (que tiende a ser repetitivo, podra mejorarse la interfaz de creacin de controles del lado del servidor) El uso de Models (la M del MVC) es algo oscuro no muy intuitivo no fomenta su uso por estas mismas complicaciones. No parece ser posible autogenerar la vista (html) automticamente (al menos en forma fcil). Por ejemplo para una aplicacin/producto grande, donde se necesite desarrollar muchas pantallas de carga.Links relacionados Temario Algoritmos III" + +} , + +{ + +"title" : "Resumen de lenguajes basados en prototipos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/resumen-lenguajes-prototipados.html", +"date" : "", +"content" : " Advertencia: esto puede ser un poco fumado.Hemos trabajado hasta aqu la nocin de objeto como la primera forma de definir conceptos, agrupar comportamiento y encapsular estado.Al objeto le puedo enviar un mensaje y el method lookup se resuelve porque el objeto receptor es el que responde al mensaje.Esta forma de definir cdigo en base a un objeto no es exclusiva de Wollok:SelfLa primera idea de tener la nocin de objeto fue Self en 1986, que naci en Xerox Parc Place como hermano menor de Smalltalk (comparten una sintaxis muy similar).Cada objeto define slots o referencias mtodosFue tambin el primero que introdujo la idea de manipulacin enteramente visual de objetos:Te dejamos dos videos que muestran cmo funciona la delegacin y cmo crear una cuenta bancariaJavascriptUn tiempo ms tarde naci Javascript (el 01/01/1997), que populariz el trmino prototype-based para los lenguajes que trabajan exclusivamente con objetos (al menos hasta la versin ES6 que incorpor las clases como syntatic sugar). Vamos a hacer el ejemplo de pepita en javascript, que pueden probar en la consola de cualquier navegador (presionando F12)// pepita es un objeto...var pepita = { energia: 0, // que tiene energia volar: function(kilometros) { // que sabe volar n kilmetros (function es equivalente al method de Wollok) this.energia = this.energia - (8 * kilometros) // y eso le resta energia (this es equivalente al self de Wollok) }, comer: function(gramos) { // que sabe comer g gramos this.energia = this.energia + (4 * gramos) }, cantar: function() { // que sabe cantar console.log("pri pri pri") }}Lo probamos en la consola del navegador// copiamos la definicin anterior de pepitapepitapepita.energia // puedo acceder a informacin de pepitapepita.comer(50)pepitapepita.volar(10)pepita.energia = 170 // incluso puedo asignar informacin de pepita sin mandar mensajespepita.descansar = function() { this.energia = 1000 } // groso! Puedo definir comportamiento nuevo// incluso puedo crear referencias nuevaspepita.durmioSiesta = false// pisamos la definicinpepita.descansar = function() { this.durmioSiesta = true this.energia = 1000}// y vemos qu pasapepita.durmioSiestapepita.descansar()pepita.durmioSiestaSimilitudes con Wollok: no estoy obligado a definir los tipos. Yo puedo enviar cualquier mensaje que un objeto entienda (as funciona el method lookup bsico). puedo definir objetos annimos y referenciarlos mediante variables el objeto agrupa comportamiento y estado (el conjunto de variables)Algunas diferencias respecto a Wollok javascript permite el acceso directo a las referencias de un objeto. Wollok nos obliga a hacerlo mediante accessors, para javacript tanto las variables como los mtodos son cajoneras donde la nica diferencia es que en las segundas guardamos expresiones lambda. javascript es dinmico: puedo agregar o modificar referencias y comportamiento sin que haya un reinicio. En esto reside su gran poder.En Wollok es necesario cambiar la referencia a un nuevo objeto para poder lograr que un mensaje pueda ser entendido:&gt;&gt;&gt; var pepita = object { }an Object[]&gt;&gt;&gt; pepita.jugar()wollok.lang.MessageNotUnderstoodException: anonymousObject does not understand message jugar()&gt;&gt;&gt; pepita = object { method jugar() { } }an Object[]&gt;&gt;&gt; pepita.jugar()&gt;&gt;&gt;Si quieren chusmear ms pueden profundizar sobre Diseo en Javascript 5 Diseo en ES6IokeIoke (06/11/2008) fue un proyecto basado en la VM de Java que propona trabajar con prototipos, intercalando lenguajes como Io, Ruby y Lisp. Vemos la misma implementacin de pepita en Ioke:pepita = Origin mimic do( energia = 0.0 comer = method(gramos, self energia += 4 * gramos) volar = method(kilometros, self energia -= (kilometros + 10)) show = method("Pepita energia: $#{energia}" println))pepita show"Pepita come 10 gramos" printlnpepita comer(10)"Pepita vuela 3 kilometros" printlnpepita volar(3)pepita showEl archivo pepita.ik tiene la definicin de pepita y luego el script que prueba cmo come y vuela.Lo evaluamos en la consolafernando@fernando-laptop ~/apps/ioke/bin $ ./ioke pepita .ikPepita energia: $0.0Pepita come 10 gramosPepita vuela 3 kilometrosPepita energia: $27.0OzonoOzono (anteriormente llamado LOOP: Learning Object-Oriented Programming) fue una herramienta desarrollada por algunos docentes de esta facultad que permita el trabajo con objetos antes de utilizar otras herramientas de Smalltalk.Otras apariciones de objectEn Scala aparece la nocin de objeto pero asociada al Singleton." + +} , + +{ + +"title" : "Robustez de los lenguajes", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/robustez-de-los-lenguajes.html", +"date" : "", +"content" : "Se dijo: NoimplementaraelsoftwaredeunacentralatmicaenRubyY eso dispar una discusin acerca de qu hace que un lenguaje de programacin, una prctica, o una herramienta sea segura para un software que no puede fallar, que debera tener la menor cantidad de errores posibles y ser tolerante a ellos en caso que ocurran.Se lleg a los siguientes vnculos de la United States Nuclear Regulatory Commission (NRC): http://www.nrc.gov/ (United States Nuclear Regulatory Commission - tiene un buscador y aparecen cosas relevantes) https://goo.gl/MibXBU (2006) http://www.sigada.org/conf/sigada2005/SIGAda2005-CDROM/SIGAda2005-Proceedings/Moore-Avoid-PL-Vulnerabilities.ppt http://web.archive.org/web/20150717074239/http://grouper.ieee.org/groups/plv/ que tiene una lista ridcula de vulnerabilidades en los lenguajes de programacin https://www.nrc.gov/docs/ML0421/ML042150288.pdf (2004 - ac se menciona a Haskell pero para validar la calidad de otro software) https://www.nrc.gov/docs/ML0634/ML063470583.pdf (1996 - ac se menciona ms que nada a lenguajes como ADA/C/C++/Ladder!)" + +} , + +{ + +"title" : "Ruby", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ruby.html", +"date" : "", +"content" : "No es este Ruby, pero les dejamos otros links interesantes:Sobre el lenguaje: Official site Ruby (wikipedia) Operador Ampersand (a veces confuso)Herramientas basadas en Ruby: JRuby MagLev RailsLa comunidad: The Ruby Programming Language Ruby Central" + +} , + +{ + +"title" : "Sabores de colecciones", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/sabores-de-colecciones.html", +"date" : "", +"content" : "Sabores de colecciones en WollokEn Wollok disponemos de dos sabores bsicos de colecciones: las listas y los sets (conjunto matemtico). Se diferencian principalmente por las siguientes caractersticas: Las listas tienen orden, los sets no, por eso slo es posible obtener un determinado elemento en base a su pocisin slo si es una lista con el mensaje get(posicionBaseCero) Los sets no admiten repetidos, las listas s, por eso si se agrega un elemento repetido a un set no se agregar una nueva referencia al mismo, mientras que en las listas se incluir una nueva referencia (en otra posicin) al mismo objeto.Literal de listas: [1,2,3] Literal de sets: #{1,2,3}Para ejemplos de uso ver Intro a coleccionesSabores de colecciones en SmalltalkSmalltalk tiene una clase llamada Collection que me permite representar colecciones, pero Collection es la abstraccin superior de la jerarqua de colecciones. Al momento de instanciar una coleccin, tengo que decidirme por un sabor. A continuacin intentaremos mostrar los sabores de colecciones, tratando de ordenarlos en base a sus respectivos grados de especializacin.Set y BagEl primer sabor que visitaremos es el Bag. Esta coleccin es de las denominadas sin orden y como su nombre lo indica, es la representacin de una bolsa. Una bolsa de objetos. Por ejemplo, al principio, hablamos de un carrito de compras. El Bag la coleccin ms adecuada para esta representacin. Imagnense que puedo poner tres latas de tomates, dos botellas de agua y siete peras.El segundo sabor que veremos es el Set. El Set, como su nombre lo indica, est concebido para la representacin de conjuntos.Una propiedad, fundamental dira, sobre conjuntos es que los elementos que pertenecen al conjunto son nicos en l. En resumidas palabras, en los conjuntos (Sets) no voy a tener dos veces el mismo elemento. O sea el Set no admite repetidos. Salvo por esta propiedad, el comportamiento es el mismo que el del Bag.Imagnense que tengo una lata de tomates y miCarrito es una coleccin. Lo voy a representar as:unaLata:=LataDeTomatesnew.unaLataconTomates:perita.unaLatadeLaMarca:LaMarcaqueaudslesgusteunaLataconPrecio:1.00Bien, tengo mi objeto unaLata y quiero agregar a mi carrito de compras 3 latas de tomates. Entonces hago:miCarritoadd:unaLata.miCarritoadd:unaLata.miCarritoadd:unaLata.Qu pasar cuando evale la siguiente lnea?miCarritosize.Yo agregu 3 veces al carrito una lata de tomates, con lo cual podra esperar que me responda 3. Pero, como vimos, si represento a mi carrito de compras con un Bag, (o sea que hice miCarrito:= Bag new.) entonces s voy a tener 3 referencias a unaLata en miCarrito.Si representara mi carrito de compras con un Set (o sea que hice miCarrito:=Set new.) entonces hubiese tenido un solo objeto dentro de mi coleccin. Simplemente, cuando hago el segundo miCarrito add: unaLata el Set identifica que ya tiene ese objeto en la coleccin y no lo vuelve a agregar.Colecciones ordenadasEntonces ya vimos el Set y Bag, que son colecciones sin orden. Ahora introduciremos algunas colecciones con orden.Qu quiere decir ordenadas? Que hay un elemento 1, un elemento 2, etc., al contrario de un Set o un Bag, en donde los elementos estn todos tirados. O sea, puedo acceder a los elementos de cualquier coleccin ordenada (veremos que hay varias variantes) parecido a como se accede a un Array en C o Pascal. Para eso le envo a la coleccin el mensaje at: , si quiero el cuarto elemento de miCol que es una coleccin ordenada, lo puedo pedir as:miColat:4y tengo los mensajes first y last que devuelven el primero y el ltimo.Eeeehhh pero si tengo un Set o un Bag, cmo accedo a los elementos de un Bag o un Set? Eso viene ms adelante. Veamos ahora las variantes de colecciones ordenadas.La primera que les presentaremos es la OrderedCollection. Esta coleccin ordena sus elementos, y el criterio es el orden en cual fueron agregados a la coleccin. Entonces si creo mi coleccin asmiCol:=OrderedCollectionnew.miColadd:'hola'.miColadd:'queridos'.miColadd:'amigos'.miColadd:'escandinavos'.despus puedo pedirle varias cosasmiColfirst&lt;-elprimero-'hola'miCollast&lt;-elltimo-'escandinavos'miColat:3&lt;-eltercero-'amigos'miColat:4&lt;-elcuarto-'escandinavos'miColsize&lt;-cantidaddeelementos-4y despus puedo seguir agregndole elementos, ante lo cual la coleccin se estiramiColadd:'agrego'.miColadd:'cosas'.miColsize&lt;-cantidaddeelementosahora-6miCollast&lt;-elltimoahora-'cosas'Luego, as como la OrderedCollection, tambin tenemos la llamada SortedCollection, que la diferencia con la primera radica en que el criterio de ordenamiento puede ser definido. Si no definimos el criterio, SortedCollection ordena los elementos por su orden natural (significa que los ordenar de menor a mayor). Dicho de otra forma, no ordena por orden de llegada, sino por comparacin entre los elementos.Si queremos ordenar los elementos de la coleccin con un criterio en particular, necesitamos pasrselo a la coleccin. La forma de hacerlo, es pasarle lo que denominamos sortBlock, que es un objeto Block (bloque).Con respecto a las colecciones que tienen orden, por ltimo veremos al viejo amigo Array. Aqu en Smalltalk tambin existe, y una de sus caractersticas es que es de tamao fijo. Para instanciar un Array, hago Array new: 6, donde 6 es la cantidad de elementos que contendr, alternativamete si conocemos los elementos de antemano pueden crearse de forma literal (que es uno de los pocos motivo razonable para querer usar un Array en vez de otro tipo de coleccin como OrderedCollection).Los Arrays no implementan el mensaje add:, justamente porque no puedo modificar su tamao. La forma de agregarles elementos es a travs del mensaje at:put:, como por ejemplo:miVector:=Arraynew:2.miVectorat:1put:unaLata.Todas las colecciones entienden una serie de mensajes que permiten obtener distintos sabores de colecciones con los mismos elementos. Estos mensajes son de la forma as{ColeccionQueQuiero}. Vamos a un par de ejemplos para ver cmo funciona.Si tuviese una coleccin de la clase Bag, y quiero sacarle los repetidos, s que el Set no tiene repetidos, entonces tomo mi coleccin como un Set. Entonces:sinRepetidos:=miCarritoasSet.Si tuviese un array, y lo quiero convertir en una coleccin de tamao variable, podra hacer:coleccionVariable:=miVectorasOrderedCollection.Si quisiera ordenar mi carrito de compras del producto ms caro al ms barato, hara algo como:ordenadosPorPrecio:=miCarritoasSortedCollection:[:unProd:otroProd|unProdprecio&gt;otroProdprecio].El mensaje asSortedCollection: recibe un parmetro que, obviamente, es un sortBlock. El sortBlock es un bloque que necesita 2 parmetros. El cdigo del bloque es un cdigo que debe devolver true o false. Para ordenar los objetos dentro de la coleccin, se evala el cdigo y si el objeto retornado es true, el primer parmetro va antes que el segundo. Si retorna false, el segundo parmetro se ubica antes que el primero.Tambin est el mensaje asSortedCollection (o sea sin el dos-puntos, o sea que no requiere parmetro) que, como dijimos antes, ordenar los elementos por el orden natural.Cul es el orden natural? Dijimos que si a una SortedCollection no le decimos cmo queremos que ordene los elementos, los ordena por el orden natural. Pero qu puede ser este orden natural?Si estoy en el paradigma de objetos seguro va a tener que ver con objetos y mensajes. El orden natural es el que dicta el mensaje &lt;, que es binario. O sea, en una SortedCollection con orden natural el criterio es poner a elem1 antes que elem2 si el resultado de evaluar elem1 &lt; elem2 es true.Claro, eso quiere decir que solamente voy a poder tener, en una SortedCollection con orden natural, objetos que entiendan el mensaje &lt;. Los nmeros, los String, las fechas, todos esos entienden &lt;. Pero p.ej. si quiero poner latas en una SortedCollection, no puede ser por orden natural, tengo que especificar el orden con el bloque con dos parmetros como vimos hace un ratito.Jerarqua de Colecciones (En Pharo)Aqu se provee una imagen con una jerarqua simplificada de las colecciones existentes en Pharo. Presten especial atencin a las clases explicadas en este artculo, las dems se proveen por motivos de completitud.DiccionariosPor ltimo, queremos mostrarles un sabor de coleccin que es especial. Se llama Dictionary y, como su nombre lo indica, intenta representar un diccionario. Este tipo de representacin implica tener una asociacin entre una clave y un valor.Poniendo como ejemplo, el propio diccionario. El diccionario es una asociacin entre una clave, que son cada letra del abecedario y un apartado de pginas que tienen palabras. El diccionario lleva todo una explicacin aparte, pueden profundizar ms al respecto leyendo sobre Diccionarios." + +} , + +{ + +"title" : "Salsa jack daniel s", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/salsa-jack-daniel-s.html", +"date" : "", +"content" : "Ingredientes 1 tea spoon cebolla en polvo 1 table spoon salsa tabasco 1/4 cup jack daniels 2 table spoon vinagre de vino 2 cup azucar rubia 1/4 cup agua 2 calditos de carne 2 table spoons worcestershirePasos: Mezclar todo en una cacerola y hasta que hierva (ojo porque sube) Dejar sobre el fuejo 10 minutos ms, a fuego bajo. Dejar que se enfre unos minutos antes de servir.NOTA: Las medidas estn en unidades americanas: 1 tea spoon = 4.92 mililitros 1 table spoon = 14.79 mililitros 1 cup = 236.58 mililitrosNOTA2: Es importante que no se pase de fuego o se va a hacer una pasta, tipo caramelo. Para evitar eso, conviene tirar cada tanto unas gotitas sobre el mrmol, hasta ver que al enfriarse se espesa, sin endurecerse. En caso de pasarse se puede cortar con un chorro de agua fra y volver a dejar que hierva." + +} , + +{ + +"title" : "Scala", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/scala.html", +"date" : "", +"content" : "Sobre el lenguaje: The Scala Programming Language Scala (wikipedia)Herramientas basadas en Scala: Play Framework Akka Scalatra Lift Scala-Test Specs2 Scala Mock SBT (Simple Build Tool) Cake Pattern y Self Type Annotations Twitter, Foursquare, Linkedin" + +} , + +{ + +} , + +{ + +"title" : "Self pseudovariable", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/self---pseudovariable.html", +"date" : "", +"content" : "**self** es una pseudovariable que **siempre** referencia al objeto receptor del mensaje que hizo que se evale el mtodo que estamos analizando en un momento dado. Ten en cuenta que no es posible asignar self, esta referencia es manejada por la mquina virtual, no por el programador.Sirve para que el objeto receptor pueda mandarse un mensaje a s mismo dentro de la implementacin del mtodo que se est ejecutando o para que, al mandar un mensaje a otro objeto que necesite colaborar con l, pueda pasarse a s mismo por parmetro.Ejemplo en Wollok:Si tenemos este envo de mensaje:`pepita.vola(10)`y pepita est definida de la siguiente forma:```object pepita { var energia = 100 method energia(){ return energia } method energia(nuevaEnergia){ energia = nuevaEnergia } methodvola(unosKms){ self.energia(self.energia()-unosKms) }}```Cuando se le mande el mensaje para volar 10 kilmetros a pepita, se va a ejecutar el mtodo que enva los mensajes para obtener y modificar la energa a self, o sea que pepita va a ser quien reciba ambos mensajes.Como se mencion antes, en cualquier mtodo es perfctamente vlido parametrizarse a uno mismo, por ejemplo:```object pepita {methodteEntrena(unEntrenador){self.come(50)unEntrenador.entrenaA(self)}}```Los mismos ejemplos anteriores, pero en Smalltalk:Envo de mensaje inicial:`pepitavola:10.`Mtodo que se ejecutara:```>> vola:unosKmsselfenergia:selfenergia-unosKms```Parametrizacin de self:```>> teEntrena:unEntrenadorselfcome:50.unEntrenadorentrenaA:self.```" + +} , + +{ + +"title" : "Self", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/self.html", +"date" : "", +"content" : "[self - pseudovariable](self---pseudovariable.html)Self - Lenguaje de programacin:- [Self (Wikipedia)](http://en.wikipedia.org/wiki/Self_(programming_language))- [Self - Sitio oficial](http://www.selflanguage.org/)" + +} , + +{ + +"title" : "Sintaxis de smalltalk", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/sintaxis-de-smalltalk.html", +"date" : "", +"content" : "La sintaxis de Smalltalk es bastante particular, pero sigue unas pocas reglas generales fciles de aprender:La regla principal es que lo primero de la sentencia es un objeto seguido por el mensaje que le queremos mandar, el cual podra o no recibir parmetros. Por ejemplo:`pepitaenergia`El objeto receptor ser aquel referenciado por la variable llamada pepita, al cual se le est mandando el mensaje energia que no recibe parmetros.`4+5`El objeto receptor es el nmero 4 y recibe el mensaje + con el parmetro 5.`pepitavola:10`El objeto receptor ser aquel referenciado por la variable llamada pepita, al cual se le est mandando el mensaje vola: con el parmetro 10. Ms sobre este tema en [Tipos de mensajes en Smalltalk](tipos-de-mensajes-en-smalltalk.html).Pero qu pasa con los elementos del lenguaje que no son envos de mensajes?Las sentencias se separan con un punto (es separador, no terminador, por eso no siempre hace falta escribirlo)`pepitavola:20.``pepitaenergia`Este cdigo primero hace que pepita vuele 20 y luego consulta su energia. En cambio esto...`pepitavola:20``pepitaenergia`... va a tratar de mandarle el mensaje pepita al nmero 20 (lo cual claramente no es lo que queramos) y como no va a entender ese mensaje, va a tirar un error.Para asignar una variable se usa := que **no es un mensaje a un objeto**, en el mtodo vola: de pepita (que tiene un atributo energia) podramos tener lo siguiente:`vola:metrosAVolar``energia:=energia-40-metrosAVolar`Lo que va a suceder es que la referencia llamada energia va a modificarse, de modo que su nuevo valor ser el resultado de la expresin energia - 40 - metrosAVolar. Slo se puede tener una referencia a la izquierda del :=, es lo nico que puede ser asignado.Para retornar el valor de una expresin en un mtodo se usa el circunflejo ^, podramos definirle el siguiente mtodo a pepita para retornar un booleano que diga si pepita tiene hambre`tenesHambre``^energia<20`El retorno corta la ejecucin del mtodo, motivo por el cual no tiene sentido tener otra sentencia luego de ^ energia &lt; 20, ya que nunca se va a evaluar.En caso de que querramos definir variables locales para un mtodo, se usan pipes | como se explica en [Variables locales en mtodos](variables-locales-en-metodos.html)Y los parntesis se usan para delimitar partes de una expresin, por ejemplo para indicar dnde comienza y dnde termina un envo de mensajes para pasar por parmetro a otro mensaje el resultado de dicha evaluacin. Sabiendo bien cmo trabaja la [precedencia](precedencia-de-mensajes.html) es posible ahorrarse muchos parntesis innecesarios haciendo que sea ms fcil de leer.Importante! No confundir parntesis ( ) con corchetes &#92;[ &#92;]. Los corchetes se usan para construir [bloques](bloques.html)." + +} , + +{ + +"title" : "Smalltalk", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/smalltalk.html", +"date" : "", +"content" : "Algunos links tiles para los que quieran conocer un poco ms sobre uno de los lenguajes ms viejitos:- [Smalltalk (Wikipedia)](http://en.wikipedia.org/wiki/Smalltalk)- [Smalltalk.org (one Smalltalk- related page to rule them all)](http://www.smalltalk.org/)Sobre (algunos de) los distintos sabores de Smalltalk:- [Pharo Project](http://www.pharo-project.org/home)- [Squeak](http://www.squeak.org/)- [GNU Smalltalk](http://smalltalk.gnu.org/)- [(Instantiations) VisualAge Smalltalk](http://www.instantiations.com/products/vasmalltalk/index.html)- [Strongtalk](http://en.wikipedia.org/wiki/Strongtalk)- [Cincom (ObjectStudio/ VisualWorks)](http://www.cincomsmalltalk.com/main/products/objectstudio/)Herramientas basadas en Smalltalk:- [Amber Smalltalk (JavaScript integration)](http://amber-lang.net/)- [Athens (a graphic library running on Pharo)](https://github.com/matthias-springer/amber-athens)- [NativeBoost](http://www.esug.org/wiki/pier/Conferences/2011/Schedule-And-Talks/Native-boost)- [tODE (the Object (centered) Development Environment)](http://code.google.com/p/tode/)- [Seaside](http://www.seaside.st/)Y la comunidad de Smalltalk:- [ESUG (European Smalltalk User Group)](http://www.esug.org/wiki/)- [FAST (Fundacin Argentina de Smalltalk](http://www.fast.org.ar/)" + +} , + +{ + +"title" : "Sobre el uso del igual en prolog", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/sobre-el-uso-del-igual-----en-prolog.html", +"date" : "", +"content" : "### Descripcin del problemaVamos a estudiar ste caso:- "Dos personas son hermanastros cuando tienen igual padre y diferente madre"### El is slo se usa para cuentas, las cuentas slo se hacen con issta solucin funciona, pero es **conceptualmente errnea**:```Prologhermanastros(Hermano1,Hermano2):-padre(Hermano1,Padre1),padre(Hermano2,Padre2),madre(Hermano1,Madre1),madre(Hermano2,Madre2),Padre1 is Padre2, %%% Ac est el errorMadre1&#92;=Madre2.```**Si el is slo sirve para cuentas,**- No es conceptualmente correcto hacer ` is Variable.`- No es conceptualmente correcto hacer ` is 4.`Si bien funciona, debemos usar las herramientas para lo que corresponde. Cuando una persona lee un is, espera cuentas. Debemos usar las abstracciones que comuniquen correctamente nuestras ideas.**Si las cuentas slo se hacen con is,**- Esto ni siquiera funciona: `Variable = 5 * 3.`.- Esto ni siquiera funciona: `factorial(N+1,Fac).` (Hay una cuenta, y falta un is!)La razn por la que `Variable = 5 * 3.` no funciona es que el `=` es "tonto", se fija que a izquierda y a derecha haya _exactamente lo mismo_. Ver [aritmtica en prolog](aritmetica-en-prolog.html).La razn por la que `factorial(N+1,Fac).` no funciona es que la unificacin que realiza prolog de valor con variable es igual de "tonta" que el `=`. Salvo que yo ponga un `is`, no se va a resolver ninguna cuenta.**Entonces:**- **S** vale `Resultado is Variable + 1.` (Siempre que `Variable` venga unificada).Ms abajo la solucin certera. ### Variable = OtraVariablesta solucin funciona, pero es **conceptualmente errnea**:```Prologhermanastros(Hermano1,Hermano2):-padre(Hermano1,Padre1),padre(Hermano2,Padre2),madre(Hermano1,Madre1),madre(Hermano2,Madre2),Padre1 = Padre2, %%% Ac est el errorMadre1&#92;=Madre2.```**Por qu est mal?** Porque tiene cierta imperatividad, en donde nosotros estamos forzando a mano que los padres sean iguales, y que las madres sean diferentes.La idea de *verificacin* que nos ofrece Lgico nos permite representar una igualdad de manera mucho ms sencilla, ms directa. Sabiendo que Prolog *considera cierta una consulta si sus variables matchean, y falsas si no*, podemos hacer las cosas ms declarativas:Si el padre *es el mismo*, entonces, *que sea la misma variable*. ste cdigo funciona, y es **conceptualmente correcto**:```Prologhermanastros(Hermano1,Hermano2):-padre(Hermano1,Padre), %%% Usamos variable Padrepadre(Hermano2,Padre), %%% Usamos misma variable Padremadre(Hermano1,Madre1),madre(Hermano2,Madre2),Madre1&#92;=Madre2.```As se aprovechan mejor las herramientas mencionadas, y redujimos un poco la imperatividad.*Que dos variables tengan el mismo nombre, es una restriccin implcita de igualdad*Por otro lado, en el caso de las variables `Madre1` y `Madre2`, como *las variables con nombres diferentes no representan una restriccin de diferencia*, tenemos que forzar dicha restriccin con el `&#92;=`.### Variable = individuoTomemos el siguiente problema: "Un instrumento suena lindo si es de cuerda y est afinado". Solucin:```PrologsuenaLindo(Instrumento):-tipo(Instrumento,Tipo), %%% Pido el tipoTipo = cuerda, %%% comparo con cuerda.estaAfinado(Instrumento).```Eso funciona, pero est **conceptualmente mal**.Por qu? Veamos:- **La unificacin de una variable se da una sola vez en la ejecucin.**Eso significa que, en un programa en lgico, los valores de las variables no cambian con el tiempo (una vez unificadas). En nuestro caso, una vez unificado con `cuerda`, la variable `Tipo` siempre es `cuerda`.- **La unificacin se da para todas las ocurrencias de la misma, e instantneamente**Eso significa que, en un programa en lgico, la variable "vale" lo mismo en cualquier parte de la regla. En nuestro caso, al unificarse `Tipo` con algn tipo en la 2da lnea, eso "llena" la variable automticamente en la 3era lnea. Y no puede cambiar el valor!En consecuencia, decir `Tipo = cuerda` es *exactamente lo mismo* que escribir `cuerda` en todos los lugares donde escribimos `Tipo`. La solucin correcta:```PrologsuenaLindo(Instrumento):-tipo(Instrumento,`cuerda`),estaAfinado(Instrumento).```Es muy comn ver este tipo de errores en predicados polimrficos y con functores. sto funciona, pero est conceptualmente mal:```Prologpotencia(Habilidad,Potencia):-Habilidad = velocista(VelMax),Potencia = VelMax.```sta es la forma **correcta**:```Prologpotencia(velocista(VelMax),VelMax).```### ConclusinEl igual es necesario en contados casos. La mayora de las veces uno se puede arreglar con la metfora de identidad de lgico, y con un poquito de unificacin y pattern matching.Usemos con criterio las herramientas y conceptos que nos da el paradigma." + +} , + +{ + +"title" : "Super", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/super.html", +"date" : "", +"content" : "**super** es una [pseudovariable](pseudovariable.html) muy parecida a [self](self.html).**super** referencia (apunta) al objeto receptor del mensaje del mtodo que estamos analizando en un momento dado al igual que **self**. La diferencia entre **self** y **super** es que **super** afecta al [ method lookup](paradigma-de-objetos---method-lookup.html)Problema que resuelve---------------------Sin la existencia de super tendramos problemas para resolver ciertos problemas, por ejemplo si tenemos la siguiente jerarqua de clases `A B`:```Smalltalk#A>>m"lgicadefinidaporAparacuandoserecibeelmensajem"^'hola'#B>>m"queremosusarlalgicaquedefineAyademshacerotracosa"^self m,'mundo'```Si a una instancia de B le mandamos el mensaje m ejecutar el mtodo m definido en B y en su definicin se manda a s mismo m, con lo cual se ejecuta ese mismo mtodo (no el de A) y as indefinidamente. Para solucionar este problema podemos usar super.```Smalltalk#A>>m"lgicadefinidaporAparacuandoserecibeelmensajem"^'hola'#B>>m"queremosusarlalgicaquedefineAyademshacerotracosa"^super m,'mundo'```Cuando en un mtodo se manda un mensaje a super el method lookup se ve modificado empezando la bsqueda del mtodo correspondiente a ese mensaje en la clase inmediatamente superior a donde est definido ese mtodo, en vez de en la clase de la cual es instancia el objeto. De esta forma podemos [redefinir](redefinicion.html) un mtodo de la superclase para agregar lgica nueva y a su vez reutilizar el comportamiento heredado.Supongamos que tenemos la siguiente jerarqua de clases `A B C` que definen:```Smalltalk#A>>m^selfn+4>>n^1#B>>m^superm+5#C>>n^3```Sabiendo que tanto **self** como **super** apuntan a **i**, o sea, ambos apuntan al objeto receptor del mensaje, analicemos lo que pasa si evaluamos lo siguiente:```Smalltalki:=Cnew.im.```Cuando i recibe el mensaje m busca un mtodo en su clase C con el mismo nombre y no lo encuentra, con lo cual lo sigue buscando en la superclase de C, que es B. All existe una definicin para ejecutar y vemos que al objeto referenciado por **super** (que es i) se le manda el mensaje m, haciendo que el method lookup para ese mensaje comience en la clase A (superclase de donde est definido el mtodo). La definicin de &#92;#A&gt;&gt;m enva el mensaje n al objeto referenciado por **self** (que tambin es i), pero el method lookup para encontrar el mtodo n comienza desde la clase de la cual es instancia i (o sea en C).El resultado final del clculo sera: 3 + 4 + 5Si le mandramos el mensaje m a una instancia de B el resultado sera: 1 + 4 + 5, ya que se ejecutara &#92;#B&gt;&gt;m que hace `self` `n`, se empieza a buscar n en B, no se encuentra, se lo busca en A y retorna 1.Resumen-------- Si el receptor del mensaje **NO** es **super**, se busca en la clase de la cual es instancia el objeto un mtodo con el mismo nombre del mensaje.- Si el receptor del mensaje ES **super** entonces se busca la definicin en la superclase de la clase en donde est el mtodo que contiene a la pseudovariable **super**.Conclusin----------*super **slo** debe usarse para **redefinir** mtodos que envan el **mismo mensaje** que se est definiendo, para **evitar loops** que se provocaran en el method lookup usando self*Malos usos de super-------------------### Caso 1Supongamos que tenemos este cdigo para la jerarqua `A B` (O sea B es subclase de A)Cdigo errneo:```Smalltalk#A>>m1"hacealgo"#B>>m1superm1```Esta redefinicin usando super es innecesaria, ya que si a una instancia de B se le manda m1 el mismo method lookup buscar la definicin en A en caso de no encontrarla en B. Es adems incorrecta, porque al redefinir un mtodo semnticamente estoy indicando que "hago las cosas distintas a arriba", cuando ste no es el caso.Cdigo correcto:```Smalltalk#A>>m1"hacealgo"```No hace falta escribir nada, B ya entiende el mensaje m1!### Caso 2Otro error muy comn (y muy grave) es usar super para mandar un mensaje con nombre diferente al mtodo que se est definiendo: (C hereda de B, B hereda de A)Cdigo errneo:```Smalltalk#A>>m1^1#B>>m2^super m1+5#C>>m1^3```En este ejemplo se puede ver que se manda el mensaje m1 en B usando super en vez de self en el mtodo m2. Esto es un problema ya que se ignora el comportamiento que puedan tener para m1 las subclases de B as como una posible implementacin futura de m1 para B. Este mal uso de super suele llevar a un comportamiento inesperado del sistema que puede no resultar en un error como sucede en este caso (retornara 6 en vez de 8), con lo cual es muy difcil de detectar y corregir.Cdigo correcto:```Smalltalk#A>>m1^1#B>>m2^self m1+5#C>>m1^3```Si yo soy un B, quiero hacer m1 como un B! Siempre voy a querer comportarme como me corresponde a m. Que ese mtodo est definido en la superclase es *una coincidencia*. Si yo quiero hacer m1, entonces hago self m1. (Releer la conclusin)" + +} , + +{ + +"title" : "Tecnicas avanzadas de programacion", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/tecnicas-avanzadas-de-programacion.html", +"date" : "", +"content" : "Tcnicas Avanzadas de Programacin - Contenidos actuales--------------------------------------------------------### Modelado en objetos avanzado- [Traits](traits.html)- [Mixins](mixins.html)- [Bloques como forma de modelar comportamiento](bloques-como-forma-de-modelar-comportamiento.html)- [Modelar comportamiento como objetos](modelar-comportamiento-como-objetos.html)### Tipado dinmico vs esttico en objetos- [Esquemas de Tipado](esquemas-de-tipado.html)- [Binding, polimorfismo y sobrecarga](binding--polimorfismo-y-sobrecarga.html)### Metaprogramacin- [Metaprogramacin](metaprogramacion.html)- [Reflection: Introspection y Self-modification](reflection.html)- [Uso de features de lenguajes dinmicos](uso-de-features-de-lenguajes-dinamicos.html)- [Method missing](method-missing.html)### Declaratividad y DSLs- [Declaratividad](declaratividad.html)- [DSL](dsl.html)- [Builder](builder.html)- [Tiempo de creacin vs tiempo de uso](tiempo-de-creacion-vs-tiempo-de-uso.html)Tcnicas Avanzadas de Programacin - Contenidos heredados---------------------------------------------------------La materia cambi mucho sus contenidos en estos aos, sin embargo el material terico sigue siendo til aunque no est en la planificacin actual.### Material terico- [Manejo de Errores](manejo-de-errores.html)- [Ciclo de vida de un objeto](ciclo-de-vida-de-un-objeto.html)- [Bibliografa](bibliografia-sobre-programacion-avanzada-orientada-a-objetos.html)- [Double dispatch](double-dispatch.html)- [Refactoring](refactoring.html)Arquitecturas-------------- [Arquitecturas](arquitecturas.html)- [Home](home.html)### Tutoriales- [Resolver problemas de dependencias maven dentro de Eclipse](resolver-problemas-de-dependencias-maven-dentro-de-eclipse.html)- Documentacin de [Arena MVC](arena-mvc.html)### Consejos prcticos- [Tips para la resolucin de un parcial de TADP](tips-para-la-resolucion-de-un-parcial-de-tadp.html)### Otros- [Frases teadepeanas](frases-teadepeanas.html)Apuntes para revisar- - [Paper about Autofetch presented at ECOOP 2006](http://www.cs.utexas.edu/~wcook/papers/AutoFetch/autofetch.pdf)Una lectura interesante- " + +} , + +{ + +"title" : "Template method", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/template-method.html", +"date" : "", +"content" : "Para calcular el precio de un producto, tenemos que considerar- todos los productos tienen un precio de venta base- los productos importados tienen un cargo extra determinado por el peso (300 $ x cada kilo)- a los productos nacionales se les suma un adicional del 10% de impuestos internos- y finalmente otros productos especiales incorporan un extra de 5 $ si el producto pesa ms de 4 kg.Si elegimos modelar los productos mediante una jerarqua de subclasificacin, tenemos- Una superclase Producto, con 3 subclases - ProductoImportado - ProductoNacional - ProductoEspecialDnde ubicamos la responsabilidad de determinar el precio de un producto?Pensamos primero en cmo resolver el precio de venta de un producto Importado `metodoprecioVenta()``precioVentaBase+(300*peso)``fin`Y el producto nacional `metodoprecioVenta()``precioVentaBase+precioVentaBase*0.10``fin`El **template method** es una tcnica que permite agrupar algoritmos similares, donde- la superclase define cmo es el algoritmo principal- cada subclase define comportamiento especfico de una parte de ese algoritmoEntonces en la clase producto definimos que el precio de venta sale del precio de venta base, y le pedimos a cada subclase que implemente el costo adicional:`metodoprecioVenta()``precioVentaBase+selfcostoAdicional``fin`En lenguajes con chequeo de tipos, Producto debe tener definido un costoAdicional en su interfaz. Esto se puede implementar- con un comportamiento default (por ejemplo, haciendo que costoAdicional devuelva 0)- o bien con un **mtodo abstracto** (abstract method), que obliga a redefinir el mtodo en las subclasesVemos la implementacin en xtend:`defdoubleprecioVenta(){``precioVentaBase+this.costoAdicional``}``defdoublecostoAdicional()//abstractmethod`En lenguajes con tipado dinmico se puede definir un mtodo que explcitamente devuelva error para obligar a las subclases a implementar cada operacin primitiva. Vemos el ejemplo en Smalltalk:`precioVenta``^precioVentaBase+selfcostoAdicional``costoAdicional``selfsubclassResponsibility`" + +} , + +{ + +"title" : "Testeo unitario avanzado", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/testeo-unitario-avanzado.html", +"date" : "", +"content" : "Este artculo presenta algunas guas para desarrollar los casos de prueba, considerando que ya tienen una base de testeo unitario automatizado. Si ests buscando un apunte, te recomendamos el siguiente [apunte de Testing](https://docs.google.com/document/d/1zj-H_qPbUDvWsWhV2YLaPsnrI0MIkCuoeK_ilzSnxVI/edit?usp=sharing).Por otra parte, aqu explicamos la mecnica utilizando JUnit 5 como framework de testeo, si ests buscando una variante al estilo XSpec, como Kotest, pods ver [esta pgina](kotest-testeo-unitario-avanzado.html).# EjemploUn sistema de seguros de automotor define en qu casos se puede pagar un siniestro:- para los clientes normales, si no son morosos (la deuda debe ser 0)- para las flotas de autos, se soporta una deuda de hasta $ 10.000 si el cliente tiene ms de 5 vehculos hasta $ 5.000 en caso contrario## Definiendo los escenariosEn base al ejemplo anterior, podemos considerar los siguientes escenarios:- un cliente normal moroso: si debe $ 1 $ 50.000 no nos importa, porque est en la misma [clase de equivalencia](https://es.wikipedia.org/wiki/Clase_de_equivalencia)- una flota con menos de 5 autos ( 5 autos) => seran "pocos" autos- una flota con ms de 5 autos => seran "muchos" autosElegimos cuntos autos en base al **valor lmite**: como a partir de los seis autos se considera mucho y menos de 6 son "pocos" autos, 6 es el valor de una flota con muchos autos, 5 es el valor de una flota con pocos autos.## Estructura de los testsLa estructura que tienen los tests en base a los escenarios propuestos podra ser:```dado un cliente normalque es moroso: no puede cobrar un siniestroque no es moroso: puede cobrar un siniestrodado un cliente de flota con muchos autos (6 autos)si el cliente debe ms de $ 10.000 no puede cobrar un siniestrosi el cliente debe $ 10.000 o menos, puede cobrar un siniestrodado un cliente de flota con pocos autos (5 autos)si el cliente debe ms de $ 5.000 no puede cobrar un siniestrosi el cliente debe $ 5.000 o menos puede cobrar un siniestro```## Definiendo las clases y las variables de los testsNecesitamos- un cliente normal- una flota de 6 autos- otra flota de 5 autosa los que podemos configurar diferentes grados de deuda. Podemos seguir algunas recomendaciones adicionales:### Agrupar los escenarios en clasesCuntas clases necesitamos para implementar los casos de prueba? Podramos considerar una clase sola para todos los tests, o bien tener dos clases: una para clientes normales y otra para clientes de flota, o bien podramos tener una clase para cada uno de los escenarios que planteamos ms arriba (cliente normal moroso, cliente que no debe nada, flota de 6 autos, etc.)Tener en una sola clase todos los tests no resulta ser una buena prctica, porque- dificulta diferenciar los escenarios, estarn todas las variables de los tests mezcladas- si construimos un fixture con cada uno de los tipos de cliente en el setup, estamos penalizando a cada uno de los tests por lo que necesitan los dems: tiene sentido crear un cliente de flota con 5 autos si estoy testeando un cliente que tiene 6?- la clase a testear pierde cohesin, est cubriendo todos los casos de pruebaVolviendo al ejemplo, hay varias opciones posibles:- tener una clase para clientes normales y otra para clientes de flota- tener una clase para clientes normales, otra para flota con pocos autos y otra para flota con muchos autosCrearemos entonces estas clases de test:- ClienteNormalTest- FlotaPocosAutosTest- FlotaMuchosAutosTestEs importante que no haya demasiados detalles de implementacin en los nombres: FlotaCon5AutosTest o FlotaCon6AutosTest est sujeto a que cualquier cambio del negocio respecto a lo que son "muchos" o "pocos" autos necesite modificar el nombre de la clase.### Intention revealing - parte 1Queremos expresar lo ms claramente posible la intencin de la clase: qu clase de equivalencia est testeando. El nombre ayuda, e incluso JUnit 5 nos permite incorporar la anotacin `@DisplayName` para describir el escenario en lenguaje castellano:```java@DisplayName("Dado un cliente de flota con muchos autos")class FlotaMuchosAutosTest {```recordando que las clases agrupan los tests, ms adelante veremos cmo juega a favor este encabezado escrito en lenguaje natural. Una vez ms recordamos: "muchos autos" es mejor que decir "6 autos". En otras palabras, explicitar el caso de prueba y no el dato de prueba: 6 autos es un dato concreto, pero lo que representa es el caso de prueba de una flota con muchos autos.## Expresividad en los tests### Un primer approachPara crear nuestro fixture de una flota con muchos autos, los enunciados suelen traer ejemplos como: "Lidia Pereyra tiene una flota con 6 autos". Es tentador escribir un test como el siguiente:```java Flota pereyra @BeforeEach def void init() { pereyra = new Flota => [ agregarAuto(new Auto("ab028122", 2008)) // ... se agregan ms autos ... // ] } @Test def void pereyraNoPuedeCobrarSiniestro() { pereyra.generarDeuda(15000) assertFalse(pereyra.puedeCobrarSiniestro) }```Pero qu pasa si hay un error en el cdigo de negocio? Supongamos esta implementacin, donde la clase Cliente tiene la definicin de la deuda como un entero:```javaclass Flota extends Cliente { List autos = newArrayList override puedeCobrarSiniestro() { this.deuda 5) 20000 else 5000 // debera ser 10.000 y no 20.000 }```Cuando ejecutamos el test tenemos muy poca informacin relevante:![mal nombre de variable](/img/wiki/testeo_mal_nombre_variable.png)- la variable `pereyra` no est revelando que es un cliente de flota con muchos autos- y tampoco est claro por qu no puede cobrar el siniestro el cliente. Al fallar la condicin tenemos que bucear en el cdigo y extraer este dato para determinar si el error est en el test o en el cdigo de negocio. ### Una segunda oportunidadVamos a mejorar la semntica del test, renombrando la variable `pereyra` por un nombre ms representativo de la clase de equivalencia que estamos modelando, agregando la anotacin `@DisplayName` para el test y definiendo un mensaje de error adicional en el assert:```javaclass FlotaMuchosAutosTest { Flota flotaConMuchosAutos @BeforeEach def void init() { flotaConMuchosAutos = new Flota => [ agregarAuto(new Auto("ab028122", 2008)) // ... agregamos ms autos ... // ] } @Test @DisplayName("si tiene una deuda grande no puede cobrar un siniestro") def void conDeudaGrandeNoPuedeCobrarSiniestro() { flotaConMuchosAutos.generarDeuda(15000) assertFalse(flotaConMuchosAutos.puedeCobrarSiniestro, "una flota que tiene una deuda abultada no puede cobrar un siniestro") }```Ahora al fallar el test sabemos ms cosas:![mas expresividad en los tests](/img/wiki/testeo_mas_expresivo_2.png)- el test con su stack trace, pero tambin- qu es lo que estamos testeando, tratando de no entrar en detalles para no duplicar lo que dice el cdigo- qu se esperaba que pasara y no pas, en un formato legible para un usuario: "Dado un cliente de flota con muchos autos, si tiene una deuda grande no puede cobrar un siniestro"## AAA PatternLos tests suelen estructurarse segn el patrn AAA: Arrange, Act y Assert.- **A**rrange: donde instanciamos los objetos a testear, con sus colaboradores: en el ejemplo son la flota y sus autos. Cuando los contextos son compartidos, los frameworks basados en xUnit (JUnit5 es uno de ellos) nos permiten ubicarlo en un mtodo `setup` (`@BeforeEach`). La desventaja de esta tcnica es que para tener una idea general de los elementos que participan en el test debemos mirar el test **y** el setup, por eso una alternativa suele ser tener mtodos en el test que construyen el escenario que se necesita:```java @Test def void conDeudaGrandeNoPuedeCobrarSiniestro() { // Arrange val flotaConMuchosAutos = this.crearFlotaDeAutos(6) // Act flotaConMuchosAutos.generarDeuda(15000) // Assert assertFalse(flotaConMuchosAutos.puedeCobrarSiniestro) }```En el ejemplo tenemos un mtodo _helper_ del test que permite crear un objeto Flota pasndole la cantidad de autos a crear. De esa manera la configuracin de una flota ocurre en una sola lnea y se puede incluir dentro del test mismo.> Una heurstica posible sobre el setup del test es tratar de mantenerlo simple y de alto nivel, ms cercano al lenguaje del dominio que con detalles de implementacin. En el ejemplo de arriba se logra con mensajes que se encargan de instanciar objetos de dominio y que esconden la complejidad de conocer la colaboracin entre la flota y sus autos). Una alternativa a tener mtodos en el test puede ser crear un objeto especfico que construya otro objeto, algo que dejaremos para ms adelante.- **A**ct: son las operaciones que tienen efecto. En el caso de la flota que tiene una deuda abultada, enviamos el mensaje que le genera la deuda. Hay tests que quizs no necesiten disparar acciones, y est bien que eso ocurra.- **A**ssert: qu esperamos que pase, generalmente asociado a las respuestas que da el envo de un mensaje al objeto testeado.### "One assert per test"Hay ciertas controversias respecto a si [podemos tener varios asserts en el mismo test](https://softwareengineering.stackexchange.com/questions/7823/is-it-ok-to-have-multiple-asserts-in-a-single-unit-test), ya que cuando el primer assert falla los siguientes no se siguen evaluando: esto en realidad depende del __runner__ de xUnit, podramos eventualmente trabajar con un framework que continue buscando asserts y discrimine cules anduvieron y cules no (RSpec, framework de testeo para Ruby, hace sto). En verdad, la heurstica que nos interesa recomendar es: **los tests deben fallar por exactamente un solo motivo**, esto relaja esa restriccin. Lo importante no es tener un solo assert, sino que todos los asserts estn relacionados con la misma funcionalidad. Dejamos un ejemplo concreto:```java@Test@DisplayName("el parser obtiene correctamente la parte numrica de la patente del auto vieja")def parsearNumerosPatenteVieja() { val lista = new PatenteParser("ABC257").parsearNumeros() assertEquals(3, lista.size) assertEquals(2, lista.get(0)) assertEquals(5, lista.get(1)) assertEquals(7, lista.get(2))}```El lector puede profundizar con estos artculos:- [Multiple Asserts Are OK](https://www.industriallogic.com/blog/multiple-asserts-are-ok/)- [Good Unit Test - One Assert](https://mfranc.com/unit-testing/good-unit-test-one-assert/)## TL;DREste es el resumen de buenas prcticas a la hora de definir tus tests:- arm los escenarios que generalmente definen las clases de tests- utiliz anotaciones `@DisplayName` para la clase de test y para cada test, de manera de entender **qu** estamos testeando. El cmo lo termins de ver en el cdigo, **evit duplicidades** entre el texto que explica y el cdigo escrito- evit que una clase de test tenga muchos escenarios juntos, es ms difcil seguirlos- los nombres de las variables deben reflejar la clase de equivalencia que estn resolviendo, y no casos particulares que no revelan la intencin de lo que estamos modelando (s `flotaConPocosAutos`, no `flotinha` o `miFlota`)- los tests se suelen estructurar utilizando las tres A: Arrange (el setup que conviene mantenerlo simple), Act (operaciones con efecto cuando corresponde) y Assert (las aserciones que deben testear el mismo concepto en cada test)## Links relacionados- Si conocs Ruby, te recomendamos [Better specs](http://www.betterspecs.org/)- [Pgina principal de Algoritmos 2](algo2-temario.html)" + +} , + +{ + +"title" : "Testing", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/testing.html", +"date" : "", +"content" : "# Testing en SmalltalkProbar una aplicacin permite verificar que el sistema (o una parte de l) funciona de acuerdo a lo especificado. Los tests permiten bajar la incertidumbre y aumentar la confianza que tenemos sobre el software que desarrollamos.Hay diferentes formas de probar una aplicacin, por ejemplo si tiene una interfaz de usuario el testeo podra realizarse manualmente siguiendo los pasos necesarios (eligiendo opciones de algn men, llenando formularios, etc) para verificar que el sistema responde de la forma esperada. Programticamente estamos acostumbrados a probar el sistema usando la funcionalidad desarrollada desde el mismo entorno de desarrollo, por ejemplo escribiendo en un workspace de Smalltalk. Supongamos que tenemos este ejemplo:```Smalltalk#Golondrina>>puedeVolar^selfenergia>20>>vola:unosKilometrosselfpuedeVolarifFalse:[NoPuedeVolarErrorsignal].selfenergia:selfenergia-(unosKilometros*2-8)pepita:=Golondrinanew.pepitaenergia:100.pepitavola:25."Leresta25*2+8deenerga"pepitaenergia."Deberaretornar42"pepitapuedeVolar."Medeberadecirquesporquetienemsde20deenerga"pepitavola:10."Leresta10*2+8deenerga"pepitapuedeVolar."Medeberadecirquenoporquetienemenosde20deenerga"pepitavola:1."Deberaexplotarporquepepitanopuedevolar"```Y al ejecutar ese workspace se puede verificar si el valor retornado por el mensaje energia luego de volar 20 kilmetros retorna el valor que esperamos que retorne, si pepita puede volar cuando tiene ms de 20 de energa y que no puede cuando tiene menos, y si efectivamente ocurre un error si se intenta volar cuando pepita no puede volar.Sin embargo existe otra forma de realizar pruebas de forma programtica que permite automatizar todo el proceso de testeo, ya que verificar que el valor de la energa de pepita sea el esperado es algo que hay que hacer manualmente. En Smalltalk vamos a usar un framework llamado SUnit (existe tambin para otros lenguajes con otro nombre, bsquenlo, aprovchenlo!) que lo que permite es codificar no slo los pasos que describen la prueba, sino tambin la validacin de los resultados esperados.Automatizar las pruebas requiere un esfuerzo extra, pero es una gran inversin porque esas pruebas quedan disponibles para ser ejecutadas N veces en el futuro. A medida que el sistema crece, la cantidad de casos a probar para verificar que el sistema completo est bien construido aumenta muchsimo, y poder asegurar que toda la funcionalidad que program ahora y que fue programada antes sigue funcionando es muy valioso.## Testing con SUnitVeamos cmo quedara el ejemplo anterior, que estaba suelto en un workspace, usando SUnit. En primer lugar, ya no va a estar suelto sino que tiene que estar en un mtodo de una clase de prueba, para indicar que es una clase de prueba y puede ser corrida como tal por la herramienta, la misma debe heredar de TestCase.```SmalltalkTestCasesubclass:#GolondrinaTestinstanceVariableNames:''classVariableNames:''poolDictionaries:''category:'Pepita-Testing'```Luego podemos agregar el mtodo para verificar que cuando pepita vuela pierde energia en funcin de la cantidad de kilmetros volados. Lo que nos requiere el framework es que los nombres de los mtodos que yo quiera que se corran como pruebas empiecen con la palabra test, lo que nos requieren las buenas prcticas y nuestra salud mental es que el resto del nombre describa lo mejor posible qu es lo que ese mtodo pretende testear. Tambin es importante poder separar la lgica en unidades atmicas e independientes, de modo que cada mtodo de test tenga un nico objetivo.```Smalltalk#GolondrinaTest>>testCuandoPepitaVuelaPierdeEnergiaEnBaseALosKilometrosVolados|pepita|pepita:=Golondrinanew.pepitaenergia:100.pepitavola:25.**self assert: pepita energia equals: 42.**```El mensaje assert:equals: lo que hace es verificar que el resultado de una expresin sea igual a un objeto esperado.Si al correr este caso de prueba pepita efectivamente queda con una energa de 42, el resultado del test ser correcto (lo cual se muestra con algn indicador verde que depender de la herramienta, como ser una bolita al lado del mtodo).Si el resultado de pepita energia es otro valor, como por ejemplo 100 (porque nuestro mtodo vola: existe pero no hace nada) el test falla, indicndose con otro color como ser amarillo, lo cual debe interpretarse como que el cdigo se pudo ejecutar sin problemas pero el resultado obtenido fue distinto al esperado. Cuando esto sucede hay que corregir el problema que bien podra estar en el cdigo de vola: como en el mtodo de test porque no describe lo que realmente debera pasar, con lo cual lo que uno hace en estas situaciones por lo general es debuggear el mtodo de test y analizar qu sucede a medida que se ejecuta el cdigo para encontrar el problema.Finalmente otra cosa que podra pasar es que el cdigo no funcione, por ejemplo si pepita no entiende el mensaje vola: se genera un error y no se puede terminar la ejecucin del test, indicndose con color rojo.Continuemos con los casos de prueba que nos faltan. Si yo quiero testear cundo puede volar pepita podramos tener dos mtodos diferentes, uno para verificar cundo s puede, y otro para verificar cundo no.```Smalltalk#GolondrinaTest>>testPepitaPuedeVolarSiTieneMasDe20DeEnergia|pepita|pepita:=Golondrinanew.pepitaenergia:100.**self assert: pepita puedeVolar**```El mensaje assert: recibe una expresin booleana, si esa expresin retorna true se considera correcto. Para hacer el otro caso en donde queremos validar que no pueda volar podramos tambin usar assert: negando la condicin (pepita puedeVolar not) o alternativamente usar el mensaje deny: que se verifica si la condicin recibida es falsa.```Smalltalk#GolondrinaTest>>testPepitaNoPuedeVolarSiTieneMenosDe20DeEnergia|pepita|pepita:=Golondrinanew.pepitaenergia:10.**self deny: pepita puedeVolar**```Por ltimo queramos verificar que si pepita no puede volar y le pedimos que vuele tiene que tirar un error. Si tuviramos este cdigo:```Smalltalk#GolondrinaTest>>testSiPepitaDebeVolarYNoPuedeTiraError|pepita|pepita:=Golondrinanew.pepitaenergia:10.pepitavola:1.```Cuando corramos este test, si efectivamente tira error porque no puede volar, el resultado que nos va a mostrar la herramienta ser ROJO. Pero si nosotros queramos verificar que tire error, cmo hacemos para transformar ese ROJO en VERDE?```Smalltalk#GolondrinaTest>>testSiPepitaDebeVolarYNoPuedeTiraError|pepita|pepita:=Golondrinanew.pepitaenergia:10.**self should: [pepita vola: 1] raise: NoPuedeVolarError**```El mensaje should:raise: espera un bloque que podra tirar error al evaluarlo, y en el caso de que suceda y el error sea instancia de la clase NoPuedoVolarError (o de alguna subclase) el resultado ser verde. Si el error no sucede, el resultado ser amarillo para indicar que no sucedi lo que se esperaba. Tambin existe la versin contraria shouldnt:raise: que verifica que el bloque no tire error.## Armando un escenarioEn todos los casos anteriores lo primero que hacemos es crear la golondrina y settearle una cantidad de energa que corresponda (una con 100 para que pueda volar, otra con 10 para que no pueda). Suponiendo que por defecto vamos a querer usar una golondrina que puede volar, con lo cual tener a pepita con 100 de energa inicial, podramos definir que antes de correr cada mtodo de prueba de la clase GolondrinaTest hay que crear a pepita e inicializarla de esa forma. Para eso el framework nos pide que definamos un mtodo llamado setUp de modo que todo lo que quiera que suceda antes de cada test se haga ah, y luego slo uso lo que se haya generado en los mtodos de test.```Smalltalk#GolondrinaTest>>setUppepita:=Golondrinanew."NtesequepepitaesunavariabledeinstanciadelaclaseGolondrinaTest"pepitaenergia:100.```Luego podemos slo hacer lo siguiente asumiento que pepita existe y tiene 100 de energa.```Smalltalk#GolondrinaTest>>testPepitaPuedeVolarSiTieneMasDe20DeEnergiaselfassert:pepitapuedeVolar```Pueden ver otros ejemplos usando tanto SUnit nativo como con LOOP en este apunte: [Apunte de Testing en Smalltalk (con y sin LOOP)](https://4924d24e-a-62cb3a1a-s-sites.googlegroups.com/site/paradigmasdeprogramacion/Cursos/sabados-a-la-manana-anual-2012/PruebasUnitariasEnSmalltalk.pdf?attachauth=ANoY7cr7qvrGe95WAgr7-ZrpqizA8HqB-2kPZ7kAk11zguNxsyp95NGD6aY9ol2dz9yT6hHVwGxE0sn4I4Ifo_Vm5K2BNYMo6WiFxa8fIYAkBhmrXUAKtsHBrjrQfcMVnaPzB-EP3dqcoFsbFC6tKTKondZAWfSDMr84oJdxnNSUJ4dNg9Ge2dziPVFRPtmeLT84gC8qvSzQ-PAYyU6yGmxqR8LzynBHC1nSwEtGSrQmFOQxt3-V7AsQF_fhhVp_k8V0Fn_1puBTyqOFg-CgZtcCvLrAD-w5jfYeulkPljDR2mQTUXpwhBRdkI7_NnDBCONjLzl9F5Ra&attredirects=0)" + +} , + +{ + +"title" : "Tipo abstracto de datos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/tipo-abstracto-de-datos.html", +"date" : "", +"content" : "# Concepto- - # Implementaciones de TADs## En C- Definir si se lo pasar por valor o por referencia- Codificar el `.h` con las declaraciones de las funciones- Si usa memoria dinmica, definir una operacin para la destruccin del TAD- Definir la estructura a emplear. Si lo hacemos en el `.c` o en el `.h` depende del grado de desacoplamiento que busquemos y nivel de paranoia que tengamos. Tambien hace mas compleja la implementacin- Definir sinnimos de tipos para la estructura.- Implementar las funciones en `.c`### ConvencionesSi bien para implementar un TAD no es necesario seguir ninguna convencin en particular, dado que C no tiene un soporte nativo para los mismos, y por tanto hay varias formas de implementarlos, es recomendable seguir convenciones para mantener consistencia en sus implemenentaciones y facilitar la comprensin del cdigo a los dems programadores (o a uno mismo en el futuro). Nosotros aqu sugerimos la siguiente:- Escribir los tipos en CamelCase. Por ejemplo *AerolineaLanchita*- Escribir las operaciones en snake&#92;_case.- Dado que nuestros TADs no presentarn polimorfismo (al menos no el los ejemplos bsicos), las operaciones estarn prefijadas por el tipo de dato, en snake case. Esto se har as para evitar colisiones en el espacio de nombres, y facilitar el autocompletado por parte del IDE. Por ejemplo *areolinea&#92;_lanchita&#92;_comprar(char &#92;* codigo&#92;_pasaje)*- Las operaciones privadas del TAD las declararemos y definiremos dentro del .c, prefijandolas con guin bajo, y declarandolas static- Respetaremos todas las buenas prcticas de programacin que ya conocemos de paradigmas: delegacin, expresividad, declaratividad (hasta donde podamos)### Ejemplo: Un bfferUn bffer es una estructura de datos similar a una cola, diseada para permitir el agregado de elementos o lotes de elementos homogeneos de forma eficiente, al final del mismom controlando su capacidad y taza de expansin para reducir al mnimo las operaciones de gestin de memoria. A diferencia de una cola, los elementos del buffer no se sacan de a uno, sino que se extraen tambin en lotes. Buffers ms avanzados soportan tambin punteros internos para delimitar regiones dentro del mismo.Por sus caractersticas, los buffers son usados tpicamente para almacenar bytes o caracteres.Modelaremos un buffer de caracteres. Este soportar las siguientes operaciones:- Creacin: se crear con un tamao inicial fijado por el usuario- Concatenacin: ofrecer una operacin para agregar un solo caracter, y otra para agregar un conjunto de caracteres.- Extraccin: expondr una operacin para extraer todos los caracteres como un char&#92;*. Una vez devuelto, es importante que el buffer pierda toda referencia al array original- Destruccin: expondr una operacin para destruir el buffer. Es importante que libere no solo la memoria usada por el buffer, sino tambin, la memoria del contenido del mismo, si no fue ya devuelto.#### Declaracin de las operacionesPensar las operaciones no se trata tan solo de pensar que funcionalidad expondr, sino tambin, y en particular cuando tenemos TADs con estado mutable, pensar cuales son las precondiciones y postcondiciones de las mismas, y las invariantes del TAD.Esta no es solo una buena prctica de diseo estructurado, sino que puede ser muy beneficiosa a la hora de trabajar en cualquier paradigma. Es decir, para especificar correctamente una operacin no basta con indicar su firma/tipo y su semntica, sino tambin sus restricciones operacionales.Estas declaraciones las colocaremos en un .h```CBuffer*buffer_new(intmax_size);voidbuffer_append_char(Buffer*self,charaChar);voidbuffer_append_chars(Buffer*self,char*chars,intcount);char*buffer_extract(Buffer*self);intbuffer_current_size(Buffer*self);voidbuffer_delete(Buffer**self);```#### Definicin de la estructura interna*Para mas detalles sobre la sintaxis, ver [Typedefs y tipos annimos](typedefs-y-tipos-anonimos.html)*Para modelar la estructura interna del buffer, utilizaremos un *struct*, que tendr un campo por cada atributo de nuestro TAD: contenido, tamao mximo y tamao actual.```Ctypedefstruct{char*content;intcurrent_size;intmax_size;}Buffer;```#### Definicin de las operaciones*Para mas detalles sobre las funciones de manejo de memoria, ver [Manejo de memoria en C](manejo-de-memoria-en-c.html)*La primera operacin que debemos soportar es la instanciacin del TAD. Esta operacin debe tomar un tamao mximo inicial, y reservar la memoria necesaria para el buffer en s mismo, y el vector de memoria donde se copiarn los contenidos. Tambin debe inicializar los atributos del TAD.Por convencin y analoga con objetos, llamaremos a esta operacin **new**:```CBuffer*buffer_new(intmax_size){Buffer*self=instance_new(Buffer);self->content=instance_new_array(char,max_size);self->current_size=0;self->max_size=max_size;returnself;}```La contrapartida de la instanciacin del TAD es la destruccin del mismo. En ambientes con Garbage Collector esto no es normalmente necesario, por lo que no existe operacin anloga en objetos. Por convencin, la llamaremos **delete**:```Cvoidbuffer_delete(Buffer**self){if((*self)->content!=NULL){instance_delete((*self)->content);}instance_delete(*self);}```Ntese que esta operacin toma como argumento una doble indireccin a un Buffer.En este caso particular, el enunciado nos plantea que solo se debe liberar la memoria del contenido del buffer, si y solo si no se ha devuelto el contenido al usuario del TAD. Para resolver esto, sealizaremos un contenido entregado al usuario setandolo en NULL.Esto mismo debemos considerarlo a la hora de justamente devolver ese contenido, mediante la operacin **extract**. Para cumplir con la precondicin de que el contenido no ha sido devuelto antes, agregaremos una asercin:```Cchar*buffer_extract(Buffer*self){assert(self->content!=NULL);buffer_append_char(self,'&#92;0');char*content=self->content;self->content=NULL;returncontent;}```Luego tenemos que encarar el problema de agregar caracteres. Llamaremos a esta operacin *'apend&#92;_chars*, que tomar como parmetro el vector de caracteres a copiar, y su longitud.La operacin no es trivial: debemos considerar que si no hay suficiente espacio en el buffer (es decir, la diferencia entre el tamao actual y el mximo es menor a la longitud del vector), deberemos redimesionar el buffer de forma eficiente.Sin embargo, an as podemos comenzar a atacar el problema, delegando apropiadamente:```Cvoidbuffer_append_chars(Buffer*self,char*chars,intcount){_buffer_expand(self,count);memcpy(self->content+self->current_size,chars,count);self->current_size+=count;}```Es decir, decimos que para copiar un vector de caracteres al final del buffer, debemos expandir nuestro buffer tanto como sea necesario para almacenar los caracteres, y luego procedemos a efectivamente realizar la copia y actualizar el tamao actual. Ahora, tenemos un problema un poco mas simple: solo debemos preocuparnos por redimensionar el buffer, de ser necesario.Dado que **&#92;_buffer&#92;_expand** no ser usada desde el exterior (es una operacin interna), no la colocamos en nuestro .h." + +} , + +{ + +"title" : "Tipos de haskell", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/tipos-de-haskell.html", +"date" : "", +"content" : "Tal vez convenga aclarar que esta no es una categorizacin terica, es ms bien una introduccin y vamos de lo ms simple a lo ms complejo.## Tipos SimplesLos tipos ms bsicos que tenemos en Haskell son los booleanos y los caracteres, que tiene los tipos y respectivamente:```HaskellPrelude>:tTrueTrue::BoolPrelude>:t'a''a'::Char```Qu podemos hacer con ellos? Algunos ejemplos con booleanos y caracteres:```HaskellPrelude>True&&FalseFalsePrelude>True||FalseTruePrelude>notTrueFalsePrelude>Char.isLower'a'TruePrelude>Char.isUpper'a'FalsePrelude>Char.toLower'A''a'Prelude>Char.toUpper'a''A'Prelude>'b'>'a'True```El tipo de los nmeros es un poquito ms complejo porque tenemos nmeros enteros, reales, racionales y muchas ms variantes, lo vamos a ver en ms detalle ms adelante. Algunas operaciones que podemos hacer:```HaskellPrelude>4*624Prelude>2+35Prelude>9-45Prelude>4`div`3 1Prelude>4`mod`3 1Prelude>4/60.6666666666666666```La divisin en ocasiones puede traer problemas de tipos, si tuviste problemas con esto le el [siguiente artculo](problemas-comunes-con-los-tipos-numericos-de-haskell.html)## Tipos Compuestos### Listas y StringsUn String es simplemente una lista de caracteres que puede escribirse con una sintaxis particular, los siguientes ejemplos son equivalentes:```HaskellPrelude>:t"Hola""Hola"::[Char]Prelude> :t ['H','o','l','a']['H','o','l','a'] :: [Char]```Para cualquier lista el tipo se escribe poniendo entre corchetes el tipo de los elementos la lista, por ejemplo una lista de booleanos:```HaskellPrelude>:t[True,False][True,False]::[Bool]```Tambin una lista de Strings (o lista de listas de caracteres):```HaskellPrelude>:t["Hola","Chau"]["Hola","Chau"]::[[Char]]```### TuplasUna tupla es tambin un valor compuesto. A diferencia de las listas el nmero de componentes es fijo y los componentes pueden ser cada uno de un tipo distinto. (Esto est ms detallado en [Cul es la diferencia entre una tupla y una lista?](cual-es-la-diferencia-entre-una-tupla-y-una-lista-.html), pero antes te recomiendo mirar los ejemplos que siguen.)Una de las tuplas ms simples que se puede imaginar es:```HaskellPrelude>:t(True,'H')(True,'H')::(Bool, Char)```es decir, una tupla compuesta por un booleano y un caracter. Sin embargo, los elementos de las tuplas tambin pueden ser compuestos, como un String:```HaskellPrelude>:t(True,"Hola")(True,"Hola")::(Bool, [Char])```o inclusive el componente de una tupla puede ser otra tupla:```HaskellPrelude>:t(False,('H',"ola"))(False,('H',"ola"))::(Bool, (Char, [Char]))```Tambin podemos tener tuplas de ms de dos componentes```HaskellPrelude>:t(True,'H',[False])(True,'H',[False])::(Bool,Char,[Bool])```es decir, un booleano, un caracter y una lista de booleanos.Para finalizar podemos ver un ejemplo en el que combianmos todo lo anterior (no es trivial, tomate tu tiempo para leerlo!):```HaskellPrelude>:t([True,False,True],"Chau",[(True,"True"),(False,"False")])([True,False,True],"Chau",[(True,"True"),(False,"False")]) ::([Bool],[Char],[(Bool,[Char])])```Es decir, una tupla de tres componentes, a saber:- Una lista de booleanos- Un string o lista de caracteres- Una lista de tuplas cuyo primer componente es un booleano y su segundo componente es un string.### TypeHaskell nos permite definir sinnimos de tipos, o sea definir un alias para un tipo concreto que se use para modelar alguna abstraccin que nos interese.Por ejemplo si modelamos a los alumnos como tuplas de aridad 2 cuyo primer elemento es el nombre y el segundo una lista de nmeros que representa las notas que se sac, podramos definir un tipo Alumno como:```HaskelltypeAlumno=(String,[Int])```De hecho, String no es ms que un alias para el tipo &#92;[Char&#92;]. Sin embargo, es importante tener en cuenta que estos sinnimos slo son tiles a efectos de declarar los tipos de otros datos o de las funciones de nuestro programa, pero para el motor de inferencia de tipos, estos alias son ignorados con lo cual si preguntamos de qu tipo es una funcin en donde se espera un alumno por parmetro, nos dir (String,[Int]) y no Alumno.### DataEs posible [definir nuestros propios tipos de dato](data--definiendo-nuestros-tipos-en-haskell.html) usando data para poder mejorar las abstracciones de nuestros programas y evitar algunos problemas asociados al uso de tuplas. Esto puede hacerse de la siguiente forma:```HaskelldataNuevoTipo=ConstructorTipo1Tipo2...TipoN```Usamos el constructor, como su nombre lo indica, para construir nuestros datos de este tipo y para hacer pattern matching como hacamos con las tuplas.```HaskelldataAlumno=UnAlumnoString[Int]fede=UnAlumno"Federico"[2,3]nombreAlumno(UnAlumnonombrenotas)=nombre>:tnombreAlumnonombreAlumno::Alumno->String>nombreAlumnofede"Federico"```El nombre del constructor puede coincidir con el nombre del tipo de dato, en este caso usamos nombres distintos para denotar que son cosas distintas y en qu contexto se usa cada una.## Funciones### Funciones con un nico parmetroEl tipo de una funcin que tiene un parmetro se indica relacionando mediante el smbolo la entrada o dominio de la funcin con la salida o imagen. Por ejemplo la funcin not recibe un booleano y devuelve otro:```HaskellPrelude>:tnotnot::Bool->Bool```La funcin isLower recibe un caracter y devuelve un booleano.```HaskellPrelude>:tisLowerisLower::Char->Bool```(Ntese que la funcin isLower est en el mdulo Char, dependiendo de su versin de Haskell tal vez deban escribir para poder probar el ejemplo, o bien importar el mdulo correspondiente.)Y la funcin and recibe una lista de booleanos y devuelve un booleano (resultado de realizar la conjuncin entre todos los booleanos de la lista)```HaskellPrelude>:tandand::[Bool]->Bool```### Funciones con ms de un parmetroLas funciones de ms de un parmetro tienen alguna sutileza porque en Haskell se trabaja con el concepto de [Currificacin](currificacion.html), entonces una funcin que nosotros en matemtica estaramos acostumbrados a verla como en Haskell la vamos a escribir . Las funciones de dos parmetros cuyo tipo tiene esa forma se denominan *currificadas*.(A los efectos de entender el sistema de tipos podemos pensarlo simplemente como una funcin que recibe dos booleanos, aunque en realidad la versin currificada es mucho ms poderosa. Para ms detalles ver la teora sobre [Currificacin](currificacion.html).)El tipo que usamos como ejemplo en el prrafo anterior corresponde (entre otros) a la funcin```HaskellPrelude>:t(&&)(&&)::Bool->Bool->Bool```### AplicacinLa [aplicacin](aplicacion.html) es uno de los temas que tal vez ms confunden cuando se habla de tipos de datos. La confusin ms frecuente radica en no diferenciar correctamente *una expresin que tiene valor Booleano* de *una funcin que devuelve Booleanos*.Ya vimos dos ejemplos de funciones que devuelven booleanos, con uno y dos parmetros:```HaskellPrelude>:tnotnot::Bool->BoolPrelude>:tChar.isLowerChar.isLower::Char->BoolPrelude>:tandand::[Bool]->BoolPrelude>:t(&&)(&&)::Bool->Bool->Bool```En este punto es importante entender que ninguno de estos ejemplos es un *valor booleano*. Cuando veo el tipo eso se entiende como el tipo *de las funciones a las que si les aplico un parmetro de tipo Char producen un valor de tipo Bool*, que claramente no es lo mismo que el tipo Bool.Lo dicho, si le aplicamos los parmetros adecuados a esas funciones, podemos obtener valores booleanos:```Haskell*Main>:tnotTruenotTrue::Bool*Main>:tChar.isLower'a'Char.isLower'a'::Bool*Main>:tand[True,False,True]and[True,False,True]::Bool*Main>:tTrue&&FalseTrue&&False::Bool```En sntesis es un valor booleano, en cambio no es un valor booleano, es una funcin que devuelve booleanos. Tambin es *un valor*, pero es un valor de otro tipo y no se pueden mezclar.Si intentamos utilizar un valor funcin en un lugar donde se espera un valor booleano, obtendremos un error:```Haskell*Main>notChar.isLower:1:4: Couldn'tmatchexpectedtype`Bool' againstinferredtype`Char->Bool' Inthefirstargumentof`not'... ```Es decir, el primer argumento de debe ser y en cambio se recibi un argumento de tipo .Similarmente:```Haskell*Main>True&&not:1:8: Couldn'tmatchexpectedtype`Bool' againstinferredtype`Bool->Bool' Inthesecondargumentof`(&&)',namely`not' Intheexpression:True&&not....```## TypeclassesSi en algn momento consultaste el tipo de una funcin y viste algo como: `Num a => ...`, `Ord a => ...` o `Eq a => ...`, significa que esa funcin puede trabajar con distintos tipos concretos (como ser Int o Float). Num, Ord y Eq (al igual que otras menos cotidianas) no son tipos, sino familias de tipos que imponen restricciones sobre qu valores pueden usarse para evaluar esa funcin. A las familias de tipos les vamos a llamar [Typeclasses](typeclasses.html)." + +} , + +{ + +"title" : "Tipos de mensajes en smalltalk", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/tipos-de-mensajes-en-smalltalk.html", +"date" : "", +"content" : "Primero arranquemos por lo bsico. Todo envo de mensaje sigue la siguiente regla: OBJETO MENSAJE PARAMETRO Lo primero que aparece es el objeto receptor, luego viene el mensaje que se le enva a dicho objeto el cual puede o no tener parmetros.Smalltalk es bastante particular en aspectos sintcticos, por eso es importante detenerse a entender cmo se interpreta. Hay 3 tipos de mensajes en Smalltalk.Los **mensajes unarios** son aquellos que no reciben parmetros, o sea que el receptor solito puede resolver lo pedido. Un ejemplo de esto sera la negacin de un booleano:`truenot``-->retornafalse`Tambin existen los **mensajes binarios** que son los que reciben slo un parmetro y su nombre est compuesto por smbolos (no alfanumrico), por ejemplo la suma entre dos nmeros es un mensaje que recibe un parmetro solo (el nmero a sumar), el otro nmero es el receptor del mensaje.`2+5``-->retorna7`Por ltimo estn los **mensajes de palabra clave** que pueden recibir tantos parmetros como sean necesarios. Estos mensajes se caracterizan por tener una o ms partes alfanumricas terminadas por el caracter : luego de los cuales se pasa cada parmetro (o sea, los parmetros van intercalados) como se muestra en los siguientes ejemplos:`5raisedTo:2``-->esunmensajequerecibeelobjeto5conunnicoparmetro,el2,yretorna25``3between:10and:25``-->esunmensajequerecibeelobjeto3conun2parmetros,el10eselprimerparmetroyel25eselsegundo,yretornafalse`Lo que tiene de simptico los parmetros intercalados es la expresividad, pero hay que ser cuidadosos de no cometer errores. Por ejemplo si quisiramos saber si el 3 est entre 10 y el 5 elevado al cuadrado debemos escribirlo de esta forma:`3between:10and:(5raisedTo:2)``-->elsegundoparmetrodelmensajebetween:and:eselresultadodemandarleraisedTo:a5conelparmetro2,lgicamentetambinretornafalse`Esos parntesis son inportantes para que se interprete como queremos y no como un nico envo de mensajes, donde el mensaje sera between:and:raisedTo: de 3 parmetros, que los nmeros no entienden!La [Precedencia de Mensajes](precedencia-de-mensajes.html) en Smalltalk se basa en estos 3 tipos de mensajes, slo nos va a interesar esta diferenciacin por ese motivo." + +} , + +{ + +"title" : "Tips para aprobar un parcial de funcional", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/tips-para-aprobar-un-parcial-de-funcional.html", +"date" : "", +"content" : "Lo que tiene que estar seguro para aprobar el parcial de funcional es [Orden Superior](orden-superior.html), [Aplicacin Parcial](aplicacion-parcial.html) y [Composicin](composicion.html).Algunas consideraciones que te llevan para el lado de la aprobacin:-Entender que cuando se aplica una funcin parcialmente lo que se obtiene es otra funcin con n - m parmetros (siendo n los parmetros de tu funcin original y m los que le aplicaste).-Entender bien la diferencia entre aplicar funciones y componer funciones entre s (nunca intentar componer cosas que no sean funciones o que al no estar suficientemente aplicadas esperen ms de un parmetro)-Usar buenas [abstracciones](abstraccion.html) tanto propias (defininiendo funciones auxiliares que ayuden a dividir el problema el problemas ms chicos) como existentes, por ejemplo en vez de hacer una funcin recursiva para trabajar con una lista usar funciones como filter, map, all, any o algn fold que se adece al problema-Pensar en los tipos de las cosas que reciben y retornan las funciones para asegurarte de que lo que ests haciendo tiene sentido. Si te cuesta el proceso de inferir el tipo de una funcin ac hay un ejemplito que est bueno para entender cmo se hace: [Clculo del tipo de una funcin en Haskell&#92;#Ejemplo un poco mas heavy](calculo-del-tipo-de-una-funcion-en-haskell-ejemplo-un-poco-mas-heavy.html)Es importante no cometer errores de los que aparecen ac: [Errores comunes al comenzar a trabajar con Haskell](errores-comunes-al-comenzar-a-trabajar-con-haskell.html). Estos errores vienen de la mano de no tener claros los conceptos de orden superior, aplicacin parcial y composicin, con lo cual se consideran invalidantes." + +} , + +{ + +"title" : "Tips para concursos docentes", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/tips-para-concursos-docentes.html", +"date" : "", +"content" : "Para un concurso hay varios consejos importantes a tener en cuenta:- tens que dar una clase como si estuvieras ante estudiantes. Osea, olvidate que hay un jurado, y habl como si hubiera estudiantes. Un error comn es hablarle al jurado y decir "ac hara tal cosa", o ms comn, saltarse partes y decir "ac explicara que esto y esto" en lugar de explicarlas. Da una clase como si hubiera estudiantes y nada ms. Otro error comn (y que a veces lo hacemos en clase tambin, pero ac es mortal) es pasar transparencias rpido y decir "esto no importa"... Si no importa, no lo pongas!!!!!- antes de la clase, explic el contexto de la misma. O sea, qumaterias hay antes y despus en el plan, qu clases se dieron en esta materia antes que la que vas a dar, y todos los conocimientos que los estudiantes se supone que tienen para que vos des la clase. Explic los objetivos de la materia y de la clase, y cmo tu clase contribuye a los objetivos de la materia. Eso muestra que ests ubicado y que conocs de lo que habls y es muy valorado por los jurados. Pero esto **antes** de empezar tu clase. Durante la clase, aplica 1.- prepar una clase como para 45 minutos, y est listo para darlacompleta. Lo ms probable es que el jurado te corte antes y te diga "listo, gracias" y ah cort y punto. O te dicen "salt hasta las conclusiones" y ah vos salts cosas. Tens que tener flexibilidad para hacer fast forward cuando te lo piden, pero siempre acordndote de 1 (o sea, es fastForward o saltear cosas, NO cambiar de modo a "y ac hara tal y cual").- El manejo del tiempo es escencial. Si te hacen ir hasta elfinal, que sean 45 minutos y no ms o menos! Adems, lo ideal es que tengas un recorrido de tu clase para 30 minutos (o sea, 15 minutos de material que no es 100% escencial, pero que contribuye). De esa manera, si al empezar te dicen "tens media hora", no tens que correr con tus 45 comprimidos, y lo hacs eliminando este material. Ten en cuenta que visto el consejo 1., tendras que tener 2 cosas preparadas... :)- Pens bien el uso de recursos y materiales de tu clase. Vas ausar transparencias? Pizarrn? Combinacin de ambos? El pizarrn, es de tiza o de fibrones? No asumas. Lo ideal es que tengas con vos borrador y fibrones (cargados) -- normalmente si es tiza, hay, pero los fibrones suelen estar chotos. Si uss transparencias, hay que avisar a concursos, y ellos te llevan el can. Pero si ests preparado para que eso no pase, mejor (en TPI tenemos caones y alguien siempre te puede alcanzar uno si aviss!) Tambin tens que estar listo para que se corte la luz y no haya can! Lo mejor para esto es tener las transparencias impresas, y repartir una copia. Es un backup muy de emergencia, pero paga. Incluso pods repartir las transparencias impresas igual, aunque puede sonar a sobreactuacin...- Cuando uses el pizarrn, administralo. Si llens el pizarrn decosas intiles, nunca lo borrs y escribs en agujeritos, es malsimo! Yo suelo tener una franja en un costado donde voy dejando "la traza" de la clase, como para que los alumnos sepan siempre dnde estamos. Y el resto lo divido en cosas ms fijas y en espacio para ejemplos (este ltimo se borra ms seguido). Hac buena letra en el pizarrn (esforzate!!!!! :)) y no des vueltas. La mejor combinacin es usar transparencias y pizarrn, administrando cada una. Pero cada profe sabe cmo lo hace mejor... :)- Respecto a la preparacin de la clase en s, ten siempre clarocul es el objetivo de la misma. Todo se arma en funcin de esto. Los ejemplos se eligen porque ilustran un concepto que contribuye al objetivo. No pongas ejemplos de ms o boludeces adicionales que no contribuyen al objetivo (a menos que el objetivo de la clase sea dar un potpurr de "boludeces"! :D). Cada transparencia debe contribuir de manera interesante al objetivo. Si arms transparencias, que haya una de ttulo, una de overview y una de conclusiones, para estructurar la clase. Que en cada transparencia quede claro de qu se habla (con un buen ttulo).- Si tens que hacer alguna demo de soft o algo as, ten todoprobado y listo! Lo ideal en estos casos es llevar tu propia compu con todo andando. No confes en las compus que puedan estar en el aula tengan todo configurado como vos espers. Si no tens compu y depends de lo que haya, entonces trat de tener una versin portable del soft, o si esto no se puede, tener un videto de lo que quers mostrar o similar... Es importante no mostrar que uno pierde media hora tratando de que un ejemplo ande." + +} , + +{ + +"title" : "Tips para la resolucion de un parcial de tadp", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/tips-para-la-resolucion-de-un-parcial-de-tadp.html", +"date" : "", +"content" : "Herramientas a utilizar (o cosas que no pueden faltar)------------------------------------------------------- Un diagrama de clases (que muestre una visin panormica del sistema)- Cdigo (en el que se ven los detalles)- Especificacin de interfaces Interfaces entrantes: Indicar cules son todas las cosas que se le pueden pedir al sistema desde afuera y para cada uno de estos posibles pedidos especificar *qu mensaje debe llegarle a qu objeto* para que el sistema lleve a cabo la funcionalidad deseada. Interfaces salientes: Definir una interfaz Java para cada una de ellas e indicar la forma en que un objeto externo que implmente esa interfaz se puede registrar en el sistema para comenzar a interactuar con l. - Diagramas adicionales - Si en alguna funcionalidad intervienen muchos objetos u ocurre una cadena larga de delegaciones, es interesante mostrar una visin global de la misma en un diagrama de secuencia o de colaboracin. - Si un objeto o una parte del sistema pasa por varios estados diferentes puede ser interesante hacer un diagrama de estados.: Es importante destacar que el diagrama no reemplaza al cdigo. El diagrama provee una visin de alto nivel de la solucin, para que quien tiene que leerlo tenga un primer pantallazo de la estrategia utilizada; luego es necesario bajar a los detalles y para eso es necesario verlos en el cdigo.- Aclaraciones adicionales que puede ser til incluir - Justificar las decisiones, contando las alternativas que se tuvieron en cuenta y la motivacin para eleccin realizada. - Potenciales puntos dbiles detectados en la solucin propuesta; junto con la justificacin de por qu se propone esta solucin a pesar de esas dificultades sealadas. - Cualquier otro comentario que ayude a comprender la solucin propuesta." + +} , + +{ + +"title" : "Traits", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/traits.html", +"date" : "", +"content" : "Un trait permite definir un conjunto de mtodos que se pueden aplicar a cualquier clase, de modo que se puedan evitar los problemas asociados a la herencia mltiple en relacin a la solucin de conflictos.Caractersticas---------------En su definicin, el conocimiento colectivo asocia a los traits con las siguientes caracteristicas:- Proveen un conjunto de mtodos que implementan comportamiento.- Pueden requerir que el usuario provea un conjunto de mtodos requeridos para su funcionamiento.- No pueden ser instanciados directamente.- No permiten definir estado interno de ninguna naturaleza.- No pueden acceder de forma directa al estado interno definido por el usuario.- Pueden ser compuestos entre ellos para generar un nuevo Trait.- La composicin de Traits es simtrica, asociativa y conmutativa y cualquier mtodo conflictivo es excluido de su resultado.- Se espera que el lenguaje provea algn mecanismo para realizar la resolucin de conflictos.- Se resuelven por [aplanamiento o flattening](flattening-vs-linearization.html).Sin embargo, a diferencia de las Clases (concepto que ha sido trasladado a varios lenguajes), el termino Trait es usado en varias tecnologas para referirse a construcciones similares, caracterizadas por un subconjunto de estas propiedades, lo cual vuelve borroso el concepto y hace difcil definir que puede o no esperarse de un Trait. Por ese motivo tomamos como implementacin de referencia a la que se encuentra en Smalltalk, desarrollada en base al paper [Traits: Composable Units of Behaviour](http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf).lgebra de Traits-----------------A continuacin se detallan las operaciones que se encuentran implementadas en Smalltalk para usar traits:**+:** Combina dos Traits en uno nuevo, el cual contiene todas las implementaciones definidas en ambos Traits.**-:** Genera una copia del Trait destino, quitando la implementacin del mensaje recibido por parmetro.**@:** Realiza una copia de la implementacin de un mensaje, utilizando otro nombre.{% link_image Operaciones-de-Traits.png %}### Solucin de conflictosEn aquellos casos en los que una clase usa dos traits que presentan implementaciones diferentes del mismo mensaje, se produce un conflicto, que debe ser resuelto en la definicin de la clase en cuestin, de lo contrario si una instancia de la misma recibe este mensaje ocurrir un error por el conflicto sin resolver.Las herramientas provistas por el lenguaje para la resolucin de conflictos se basa en las operaciones - y @ definidas anteriormente y en la premisa de que si se define el mismo mensaje en la clase o trait en conflicto, esta definicin tendr mayor peso, con lo cual las otras definiciones dejan de usarse y el conflicto desaparece.Por ejemplo, si la clase A usa a los traits B y C, y tanto B como C definen &#92;#m algunas posibilidades para resolver el conflicto de &#92;#A&gt;&gt;m son:- Restarle a uno de los traits el mensaje &#92;#m, con lo cual slo existir una implementacin, por ejemplo:`Objectsubclass:#A``uses:B-#m+C``...`- Definir la implementacin real para A usando un alias para los mtodos de traits, por ejemplo:`Objectsubclass:#A``uses:B@#{#mDeB->#m}+C@#{#mDeC->#m}``...`y luego...`#A>>m``selfmDeB.``selfmDeC.`Si no se define &#92;#A&gt;&gt;m adems de definir los alias, el conflicto sigue existiendo.Cmo diseamos con Traits?---------------------------Algunas teoras dicen que todo el comportamiento debera estar en los Traits (ver paper de Ducasse citado), segn esas ideas una clase se define como:`Superclase+Traitcomposition(conjuncindevariostraits)+Estado+Gluecode`Por otro lado existe el enfoque opuesto de modo que los Traits slo se usan como *parches* para el modelo con herencia simple de modo que se eviten las repeticiones de cdigo. Si slo se busca extraer el cdigo repetido, el Trait extrado podra no tener consistencia semntica y no conformar una entidad representativa, volvindose difcil de reutilizar y generando abstracciones pobres.No hay ideas muy formadas an sobre cmo disear con traits y herencia simple dndoles igual peso a ambas herramientas, por lo tanto en principio, seguir el primer enfoque y a partir de ello poder descubrir mejores alternativas es una estrategia interesante para el aprendizaje.Traits y super--------------La meta-variable super se usa para modificar el Method Lookup de modo que sea posible redefinir mtodos heredados y a su vez reutilizar la definicin de la Clase padre.El uso de super en un mtodo de Trait es tcnicamente posible ya que estos mtodos sern invocados en el contexto de las Clases usuarias donde existe una superclase de la cual se heredan definiciones de mtodos. Sin embargo esto implica que el Trait slo pueda ser usado en contextos en los cuales la superclase tenga una implementacin del mensaje enviado en el mtodo de Trait, quedando altamente acoplado con los usuarios del mismo y por lo tanto disminuyendo su reutilizabilidad.Papers------- [Traits: Composable Units of Behaviour &lt;- **el paper de Ducasse**](http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf)- [Stateful Traits](http://scg.unibe.ch/archive/papers/Berg07aStatefulTraits.pdf)" + +} , + +{ + +"title" : "Transparencia referencial efecto de lado y asignacion destructiva", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/transparencia-referencial--efecto-de-lado-y-asignacion-destructiva.html", +"date" : "", +"content" : "Definiciones------------**Operacin:** aplicar una funcin, evaluar un predicado, enviar un mensaje, etc.**Transparencia Referencial**Hay transparencia referencial si al reemplazar una operacin por su resultado se logra el mismo efecto.Una definicin alternativa dice: Hay transparencia referencial cuando al realizar una operacin con los mismos valores siempre da el mismo resultado. Si bien esta parece ms fcil de entender, no es tan precisa como la primera; puede ser til para dar los primeros pasos, pero para el final hay que terminar de entender la otra.Tambin se puede pensar en las propiedades necesarias para tener Transparencia Referencial.Decimos que una operacin tiene transparencia referencial si es:- Independiente: No dependen del estado de nada que este fuera de s misma- Sin estado/Stateless: No tiene un estado que se mantenga de llamada en llamada- Determinstica: Siempre devuelven el mismo valor dados los mismos argumentos- No produce efecto colateral**Efecto de Lado/Colateral (Side Effect)**Hay efecto cuando un cambio de estado sobrevive a la realizacin de una operacin. Por ejemplo, una operacin puede modificar una variable global, modificar uno de sus argumentos, escribir datos a la pantalla o a un archivo, o hacer uso de otras operaciones que tienen efecto de lado.Otra definicin vlida es: Si le sacs una foto al sistema (llammosla F1), despus realizas la operacin de tu inters, y le volvs a sacar una foto al sistema (F2). Si F1 y F2 son distintas =&gt; la operacin que hiciste tiene efecto de lado.**Asignacin Destructiva**Asignar destructivamente es reemplazar el valor de una variable por otro valor.La [unificacin](unificacion-y-pattern-matching.html) no se considera asignacin (al momento de ligar no haba ningn valor anterior, sera ms bien una inicializacin?). Unificar es encontrar una sustitucin capaz de igualar 2 trminos. Cuando se efectiviza est sustitucin hablamos de ligado de variables (tal valor se lig a tal variable).Ejemplos--------Cuando hablamos de que "algo" tiene transparencia referencial, efecto colateral o asignacin destructiva, ese "algo" es la realizacin de una operacin, de un lenguaje en particular o de un paradigma.Estos tres conceptos suelen ir de la mano y si bien pueden darse relaciones entre ellas es saludable poder detectar la aparicin de cada uno de ellos individualmente. Una relacin que surge de la definicin de transparencia referencial es que para sta se d, no puede haber efecto colateral, ya que si el estado del sistema se modifica, o se escribe en un archivo por ejemplo, no es lo mismo ejecutar esa operacin que reemplazar por el resultado.A continuacin mostramos algunos ejemplos en el [paradigma orientado a objetos](paradigma-de-objetos.html), ya que permite la aparicin de todas estas caractersticas, para dejar ms en claro de qu manera podemos identificarlas.### Ejemplo 1: consulta no determinsticaEl siguiente cdigo crea una fecha, configurada para representar el da de hoy: `new Date()`- Transparencia Referencial: NO (Con cualquiera de las 2 definiciones de transparencia referencial)- Efecto: NO- Asignacin Destructiva: NOEvaluarlo con los mismos parmetros (o sea ninguno) en das distintos va a dar resultados distintos. Reemplazar la operacin por el resultado una vez que cambia el da se rompe todo. Asignacin destructiva y efecto no hay, o al menos no es relevante (se est creando un nuevo objeto en el sistema, pero en general no lo vamos a considerar para nuestro anlisis, y tampoco tiene que ver con el hecho de que un da responda una cosa y otro da otra).Ejemplos como este hacen que transparencia referencial y efecto colateral no sean conceptos opuestos, ya que en este caso se debe a que la operacin depende de algo externo (la fecha de la computadora).### Ejemplo 2: mtodo con efectoDada la siguiente implementacin del objeto pepita:```object pepita { var energia = 100 method vola(metros) { energia = energia - (metros + 4) }}```Analicemos el mensaje: `pepita.vola(20)`- Efecto colateral: SI, porque la energa de pepita antes era 100 y luego es 76.- Transparencia Referencial: NO, se est produciendo un efecto al disminuirse la energa de pepita. En este caso el mtodo no retorna un valor, con lo cual no tendra sentido intentar reemplazar ese envo de mensajes por su resultado.- Asignacin destructiva: SI, al hacer energia = ... estamos cambiando a qu objeto referencia por esa variable.### Ejemplo 3: mtodo de consulta determinstica```object factorial { method para(numero){ var resultado = 1 if(numero > 0) resultado = self.para(numero - 1) * numero return resultado }}```Analicemos el mensaje: `factorial.para(20)`- Transparencia Referencial: SI, el resultado slo depende de sus argumentos, no importa en qu contexto, siempre dar el mismo resultado para el nmero 20.- Asignaciones Destructivas: SI, podemos ver que la variable local resultado primero toma el valor 1, pero luego para nmeros mayores a 0 se modifica por el valor que corresponda.- Efecto colateral: NO, a pesar de que hay una asignacin dentro del mtodo, al ser slo una variable local no se produce ningn efecto que perdure a la ejecucin de ese mensaje. Esa asignacin podra analizarse como efecto colateral dentro del mtodo. Probablemente en un mtodo tan pequeo como este no tenga importancia ese tipo de anlisis, pero en el caso de algoritmos ms complejos podra cobrar valor (y asumiendo que no sea posible partir un algoritmo complejo en operaciones ms pequeas que simplifiquen justamente el anlisis, pero eso ya es otra cuestin).Por qu nos interesa pensar en estos conceptos?------------------------------------------------Estos son algunos ejemplos concretos sobre cmo la existencia o no de efecto, asignacin destructiva y transparencia referencial afectan a la hora de programar.**Separar la lgica que hace cosas de la que consulta:** Muy seguido vemos mtodos (o procedimientos, dependiendo del paradigma) que tienen efecto y a su vez retornan algn valor relacionado con el mismo, estas prcticas pueden llevar a confusiones que producen un funcionamiento errneo del sistema, sobre todo cuando el nombre del mtodo elegido no denota que existe un efecto asociado a su ejecucin. Es una buena prctica tener separada la lgica que realiza modificaciones sobre el sistema de los que slo pretenden obtener el resultado de una consulta, que nuestros mtodos tengan un nico objetivo, lo cual simplifica su uso y la eleccin de un nombre suficientemente representativo.**Respetar los contratos blandos:** Un contrato blando es algo que cierta pieza de cdigo requiere que cumpla el usuario para que la misma funcione de la forma esperada, pero esos requisitos no son validados de ninguna forma. Un ejemplo tpico de esto est relacionado con los [mensajes de colecciones](mensajes-de-colecciones.html) que esperan recibir un bloque de cdigo que sea slo de consulta, o sea que no produzca ningn efecto.**Optimizaciones:** Tener asegurada la transparencia referencial permite hacer optimizaciones como las que tiene el motor de Haskell que afectan globalmente a los programas construidos con el mismo. La [evaluacin perezosa o lazy](estrategias-de-evaluacion.html) es posible gracias a esta caracterstica. Tambin lo podemos ver en Prolog que para buscar soluciones utiliza el mecanismo de [Backtracking](backtracking.html) de modo que se puedan encontrar mltiples respuestas a una consulta, as como descartar los caminos por los cuales no sea posible hayar alguna, de una forma eficiente.Otro ejemplo viene de la mano del procesamiento en paralelo. Si tenemos un conjunto con millones de elementos y queremos filtrarlo por un criterio, no puedo dividir ese conjunto en varios ms pequeos, filtrarlos por separado en distintos procesadores y juntar sus resultados? Si yo aseguro que evaluar el criterio de filtrado sobre cada elemento no va a provocar ningn efecto que pueda alterar mi resultado final, esta optimizacin podra permitir aprovechar mucho mejor el hardware disponible. Si te interesa el tema ac hay algo para leer al respecto: [Scala - Parallel Collection Framework](http://infoscience.epfl.ch/record/150220/files/pc.pdf)**[Testing](testing.html):** El testeo unitario se basa en la premisa de que cada test sea independiente del otro y eso se logra controlando que el estado del sistema antes y despus de correr cada test sea el mismo, por ese motivo es importante mantener el efecto controlado y poder revertir aquellos cambios que sobrevivan a la ejecucin de cada test particular. Tambin la transparencia referencial es importante para el testeo unitario ya que testear el resultado de una operacin que depende de algo no determinstico no es viable y hace falta usar estrategias de testeo ms avanzadas ([Mock Objects](http://es.wikipedia.org/wiki/Objeto_simulado)) para evitar este tipo de dependencia.Preguntas frecuentes--------------------Le una definicin de Transparencia Referencial: Hay transparencia referencial si al reemplazar una operacin por su resultado se logra el mismo efectoCon este criterio, aqu s habra transparencia referencial:```inta=1;intc;c=a++;```Ya que es lo mismo que hacer esto:```inta=1;intc;c=1;```Ya que el efecto en la variable c es el mismo: va a valer 1.Pero para m no es as, ya que no va a haber transparencia referencial, porque si bien se logra el mismo efecto con respecto a c, el sistema cambia (la variable a se incrementa en una unidad).Es correcto afirmar entonces que si no hay Efecto de Lado entonces tengo garantizada la Transparencia referencial y viceversa?> En el ejemplo dado no hay transparencia referencial, es correcta la interpretacin. La expresin a++ tiene el efecto colateral de modificar el valor de a, por lo tanto no puede tener transparencia referencial. Sin embargo, no es correcto que si no hay efecto entonces est garantizada la transparencia referencial (como se pone en evidencia en el ejemplo de la consulta no determinstica)." + +} , + +{ + +"title" : "Interfaces y union types en Typescript", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ts-tipado.html", +"date" : "", +"content" : "# Un enunciado## Resolucin con interfaces## Resolucin con union types" + +} , + +{ + +"title" : "Tutorial de squeak y pharo", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/tutorial-de-squeak-y-pharo.html", +"date" : "", +"content" : "Empezar a usar el Squeak puede ser un poco complicado porque no es muy intuitivo, les dejamos una explicacin para poder arrancar con menos miedo. Pharo no es muy diferente, as que slo aclaramos cuando difiere para no armar todo de nuevo :DCrear una Clase---------------1) Abrir el Class Browser (System Browser): Hagan click sobre el fondo del squeak para que se les abr el men World -&gt; open... y eligen Class Browser (en Pharo se llama System Browser)2) En la primer columna del Class Browser tienen las categoras, all deberan crear una nueva para agrupar las clases que vayan haciendo. Para eso hacen click derecho sobre esa columna y eligen add item... (en Pharo es Add Category) Les va a pedir que ingresen el nombre para la categora, por ejemplo, TPObjetos-grupoBle (no s si haba algn formato requerido, pero pongan algo que los identifique).Al darle OK les va a aparecer el template para crear clases dentro de esa categora:`Objectsubclass:#NameOfSubclass``instanceVariableNames:''``classVariableNames:''``poolDictionaries:''``category:'TPObjetos-grupoBle'`3) Crear clases: Siempre que quieran crear una clase nueva hacen click sobre el nombre de la categora para que les aparezca el template anterior. Lo que tienen que hacer es cambiar NameOfSubclass por el nombre real, por ejemplo, Pelicula; despus para agregarle variables de instancias tienen que escribir los nombres entre las comillas simples de instanceVariableNames separadas por espacios. Si tuvieran variables de clase iran en el rengln de abajo. Recuerden que las de instancia empiezan con minscula y las de clase con mayscula por convencin. Finalmente, si quisieran que herede de otra clase que no sea Object, cambian Object por el nombre de la superclase.Para dar los ejemplos vamos a usar la parte ms bsica de un parcial/tp "Salas de Cine":*Se desea hacer un sistema para una cadena de cines, en la cual guardar la informacin de las salas que administra la cadena y las pelculas que se dan en cada horario en cada una de esas salas. Para simplificar asumimos que todas las pelculas comienzan en punto y que duran una cantidad entera de horas. Adems de su duracin, de cada pelcula se sabe su gnero.*`Objectsubclass:#Pelicula``instanceVariableNames:'duraciongenerotitulo'``classVariableNames:''``poolDictionaries:''``category:'TPObjetos-grupoBle'`Una vez que completaron el template hacen click derecho -&gt; Accept o simplemente Ctrl+S.Si quieren editar la definicin de la clase, por ejemplo para agregar/quitar variables o cosas as, clickeando sobre el nombre de la clase debera mostrarles el cdigo que guardaron y vuelven al paso 3.Para crear una subclase pueden cambiar el template para que use la superclase en vez de Object. Ms detalles, ac: [Cmo crear una subclase en Squeak](como-crear-una-subclase-en-squeak.html)Mtodos-------### Creando un Mtodo4) Agregar mtodos: Haciendo click sobre la 3er columna (donde tienen --all-- y no messages) les aparece un ejemplo de cmo quedara un mtodo:`messageselectorandargumentnames``"commentstatingpurposeofmessage"``|temporaryvariablenames|``statements`Eso lo borran y escriben el mtodo que tengan ganas. Por ejemplo:`verificarLongitud``"Estodeabajoesfruta,peroparaqueseimaginencmopodraescribirseunmtodo"``^selfgeneronombresize>10ifTrue:[30]ifFalse:[20]`Ac se estn usando 2 mensajes an indefinidos: genero y nombre, que son los getters de las variables de instancia. Los accessors se pueden crear directamente haciendo click derecho en el nombre de la clase y... En Squeak: -&gt; more... -&gt; create inst var accessors En Pharo: -&gt; Refactor Class -&gt; Accessors (para crear todos los que falten)`->Refactorinstancevariable->Accessors(paraelegirunavariableparacualcrearlosaccessors)`Como todava no haba hecho eso al hacer Ctrl+S al mtodo verificarLongitud para aceptar y que se agregue efectivamente debera aparecer un cartelito diciendo que no conoce esos selectores porque no hay ninguna clase que defina genero y nombre, entonces les tira un par de opciones por si se confundieron, siendo la primera lo que tipearon, las siguientes algunas alternativas existentes y al final Cancel para seguir editando el mtodo sin aceptar los cambios.Mucho ms que eso no hay para lo que es definir las clases. Lo que quedara es armar el programita -&gt; workspace (no main =P). Lo que tiene de copado es que tienen un ambiente vivo y pueden mandarles mensajes a los objetos como se les de la gana, no es necesario tener todo el programa armado y darle run, lo pueden ir armando a la par que le agregan los mtodos a las clases. As que...### Modificando un MtodoPara modificar un mtodo, si se equivocaron, pueden hacerlo seleccionando el mtodo, haciendo los cambios y apretando aceptar. Pero Ojo! ''' No se puede modificar as noms el nombre de un mtodo. ''' Si se quiere cambiar su **selector** (cualquier cosa del nombre los parmetros) debern hacerlo as:- Clck en la lista de mtodos sobre el que quieren modificar- Botn derecho en el mtodo -&gt; **refactor method**Y ah les ofrece varias cosas, eligen lo que quieren hacer.Escribir Un Workspace---------------------5) El Workspace: Volvemos al fondo del Squeak, hacen click para que aparezca World -&gt; open... -&gt; workspaceAh les aparece un cuadro de texto en blanco para que tiren cdigo. Lo primero que podemos hacer es instanciar una Pelicula y settearle un par de atributos. As que escribimos lo siguiente en el workspace:`saw:=Peliculanew.``sawtitulo:'ElJuegodelMiedo'.``sawduracion:2.`Si seleccionan esas tres lneas (para seleccionar todo tienen Ctrl+espacio) y hacen Ctrl+d (do it) se evalua ese cdigo. Para ver si anduvo todo bien pueden escribir lo siguiente en el workspace:`sawtitulo.`Si se paran al final de ese rengln (para evaluar una sola lnea no es necesario seleccionar, si seleccionan todo se va a evaluar todo desde el principio nuevamente y eso no tiene gracia, jeje) y le dan Ctrl+p (print it) les va a aparecer al final de la lnea y seleccionado para su conveniente borrado el string 'El Juego del Miedo'Otra forma de ver qu onda con nuestros objetitos es pararse sobre la variable con la que lo referenciamos, en este caso saw, y hacer ctrl+i (inspect it). Eso les abre una ventanita donde pueden ver a qu est referenciando cada una de las variables. En este caso tendran lo siguiente:``**`self` `->` `a` `Pelicula`**``**`all` `inst` `vars:`**``**`duracion:` `2`**``**`titulo:` `'El` `Juego` `del` `Miedo`**`'```**`genero:` `nil`**Claro, el genero est en nil porque no le setteamos nada, de hecho ni siquiera creamos la clase Genero. Hagamos eso as probamos verificarLongitud...Creamos la clase Genero dentro de la categora TPObjetos-GrupoBle con las v.i. que quieran, incluyendo nombre. Despus create inst var accessors y listo.Volvemos al workspace... agregamos el siguiente cdigo:`terror:=Generonew.``terrornombre:'Terror'.``sawgenero:terror.````sawverificarLongitud.`Seleccionamos ese cdigo y le damos ctrl+p y al final de ese cdigo seleccionado aparece el nmero 20 que es lo que esperbamos.Mtodos de Clase----------------5) Mtodos de clase: supongamos que el gnero lo quieren instanciar directamente como:`terror:=GeneroconNombre:'Terror'yDuracionMaxima:1.5.`Ah habra que escribir el mtodo de clase conNombre: yDuracionMaxima: Para eso vamos a la clase Genero en el Class Browser y hacemos click en el botoncito que dice class (hasta ahora venamos trabajando del lado de las instancias). De manera anloga, hacemos click en la tercer columna para que nos aparezca el ejemplo de mtodo y escribimos lo siguiente:`conNombre:unNombreyDuracionMaxima:unaDuracion``^selfnew``nombre:unNombre;``duracionMaxima:unaDuracion.`Ah lo nico loco que hice fue usar un truquito que no contamos en clase me parece que es el de enviar mensajes en cascada. La forma de evaluacin de ese cdigo sera: primero self new por ser unario, eso me da una instancia de Genero, a esa instancia se le enva el mensaje nombre: con el parmetro que nos lleg de afuera unNombre. El punto y coma indica que la siguiente sentencia es un mensaje que se le enva al mismo objeto de antes, o sea al genero que instanciamos recin. Le mandamos duracionMaxima: y le setteamos la duracin correspondiente.Finalmente retorna al objeto ya inicializado (el ^ es lo que tiene menor precedencia) y lo que va a retornar es lo que haya retornado el ltimo envo de mensajes. Como duracionMaxima: es un setter por defecto que no tiene ningn ^ estamos seguros de que lo que va a retornar (porque TODOS los mensajes retornan un objeto) es al objeto receptor.A modo informativo, si duracionMaxima: retornara algo diferente de self habra que hacer lo siguiente:`conNombre:unNombreyDuracionMaxima:unaDuracion``^selfnew``nombre:unNombre;``duracionMaxima:unaDuracion;``yourself.`Para que nos retorne al objetito receptor.La otra alternativa que a m me resulta medio incmoda pero es la ms fcil es definirle un mensaje de instancia al gnero que sea nombre: yDuracionMaxima: que le settee internamete las dos variables al objeto. Con lo cual quedara lo siguiente:`conNombre:unNombreyDuracionMaxima:unaDuracion``^selfnewnombre:unNombreyDuracionMaxima:unaDuracion.`Y del lado de las instancias (hacemos click en instance) agregamos el mtodo nombre: yDuracionMaxima: que haga lo siguiente:`selfnombre:unNombre.``selfduracionMaxima:unaDuracion`Y no retornamos nada porque queremos que nos retorne self.Ahora podemos refactorizar nuestro workspace y nos quedara algo as:`saw:=Peliculanew.``sawtitulo:'ElJuegodelMiedo'.``sawduracion:2.````terror:=GeneroconNombre:'Terror'yDuracionMaxima:1.5.``sawgenero:terror.````sawverificarLongitud.`Hacemos Ctrl+space + Ctrl+p y mgicamente sigue dando 20 =D O sea que hicimos las cosas bien y no rompimos nada.Guardando nuestro trabajo-------------------------### Grabar la Imagen6) Guardar los cambios: Hagan click en el fondo para abrir World -&gt; save### Grabar en un archivo .st7) FileOut: Para hacer la entrega tienen que hacer un fileOut de la categora. Para eso slo le dan click derecho al nombre de la categora -&gt; fileOut. Cuando yo lo hice no me pregunt en dnde guardar ni con qu nombre, simplemente se guard en mi directorio de instalacin del Squeak con el nombre de la categora y extensin .stNo se preocupen si ven muchos !!!! en el archivo, es lo que tienen que pasar. Despus de todo no fue hecho para ser ledo por mortales, nada ms para ser importado en otro Squeak o para los paspados que prefieren la entrega en papel, jajajaj (mentira, es til tenerlo en papel, y con un poquito de cancha es hasta fcil de seguir)### Grabar el Workspace8) Guardar el Workspace: obviamente el fileOut slo les guarda el cdigo de las clases que estn en la categora, el ws hay que guardarlo aparte. Pueden hacer simplemente copy/paste y pegarlo a un txt normal o pueden usar la opcin de guardado que trae el Squeak. Para eso: click derecho sobre el workspace -&gt; more... -&gt; save contents to fileLe ponen el nombre que quieran y la extensin la pueden dejar como txt o cambiarla a st, que es como se guarda en la otra versin de Smalltalk. Se los va a guardar en la misma carpeta por default en la que se hizo el fileOut.### Importar un archivo .st- Arrastrar el archivo .st y soltarlo sobre la imagen de Pharo. Le dan **FileIn Entire File** y Listo!- Otra forma: 1) Botn derecho sobre el fondo. En el men **World** van a **Tools -&gt; File Browser**.2) En el File Browser van a ver tres paneles:el de la izquierda muestra el arbol de directorios y carpetas de su sistema.3) Seleccionar la carpeta donde esta instalado Pharo, que es donde va a estar el archivo .st que quieren importar. En el panel de la derecha, van a ver la lista de los archivos incluidos en esa carpeta.4) Seleccionen el archivo .st. En el panel inferior van a ver el codigo que escribieron, y arriba de los paneles superiores van a aparecer varios botones, elijan **Install**Shortcuts / Atajos del Teclado / Fatalities-------------------------------------------- **Ctrl+b** seleccionando una clase&#92;* para que se abra un Class Browser sobre esa clase.- **Ctrl+n** seleccionando un selector&#92;* para ver sus Senders (se abre una lista de mtodos desde donde se enva ese mensaje, tambin vale para cuando se usa un symbol igual al mensaje, onda &#92;#size).- **Ctrl+m** seleccionando un selector&#92;* para ver sus Implementors (se abre una lista de mtodos para ese mensaje)- **Ctrl+shift+n** sobre una clase&#92;* para ver en dnde se usa (References)- **Ctrl+i** sobre un objeto nos permite inspeccionarlo por adentro- **Alt+punto** para mandar una interrupcin (til para cuando uno se la manda y queda ejecutando algo recursivamente, se interrumpe la ejecucin y se puede debuggear el stacktrace desde donde interrumpimos)&#92;* En cualquiera de estos casos, "seleccionar" se puede entender como seleccionar un selector / nombre de clase dentro de un cacho de cdigo (workspace, definicin de un mtodo en el class browser, el debugger, etc), o bien seleccionarlo en un listado de cualquier browser (el Class Browser, la lista de variables de instancia y temporales que aparece en un debugger, una lista de senders que hayas abierto, etc).Por cierto, todas las cosas que se listan con Ctrl tambin funcionan con Alt en Windows (a veces slo funcionan con Alt)." + +} , + +{ + +"title" : "Tutorial de squeak", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/tutorial-de-squeak.html", +"date" : "", +"content" : "1. REDIRECT [Tutorial de Squeak y Pharo](tutorial-de-squeak-y-pharo.html)" + +} , + +{ + +"title" : "Tutoriales para desarrollo java", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/tutoriales-para-desarrollo-java.html", +"date" : "", +"content" : "- [Preparacin de un entorno de desarrollo Java](preparacion-de-un-entorno-de-desarrollo-java.html) (basado en Java, Eclipse, Svn y Maven)- [Crear un proyecto en xp-dev](crear-un-proyecto-en-xp-dev.html)- [Publicar un proyecto en svn](publicar-un-proyecto-en-svn.html)- [Creacin de un proyecto maven bsico](creacion-de-un-proyecto-maven-basico.html)- [Checkoutear un proyecto maven de un repositorio svn](checkoutear-un-proyecto-maven-de-un-repositorio-svn.html)- [Resolver problemas de dependencias maven dentro de Eclipse](resolver-problemas-de-dependencias-maven-dentro-de-eclipse.html)" + +} , + +{ + +"title" : "Typeclasses", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/typeclasses.html", +"date" : "", +"content" : "# IntroduccinProblema--------Si tenemos la multiplicacion (&#92;*) definida para tanto Int como Float, luego`squarex=x*x`debera transformarse en tiempo de compilacin en dos funciones distintassquare (para ints) square (para floats)Lo cual crece exponencialmente, por ejemplo con funciones como`squares(x,y,z)=(x*x,y*y,z*z)`que sera traducida en 8 funciones distintas, de modo que se pueda usar tanto con una tupla de tipo (Int, Float, Int) como (Float, Float, Float) o (Int, Int, Float)...Typeclasses al rescate----------------------Las typeclasses son un contrato o tipo de datos abstracto que agrupa las funciones sobrecargadas: es decir, definen una lista de funciones que un tipo deber implementar para considerarse de esa clase. Ejemplo: la typeclass Num dice que todos aquellos tipos que sean Num (Int o Float por ejemplo) van a definir las funciones (+) y (&#92;*) y de que tipos son.Las typeclasses tienen como primer consecuencia que funciones como squares, que tena 8 tipos posibles, tenga uno solo:`squares::Numa,Numb,Numc=>(a,b,c)->(a,b,c)`Donde Num es un typeclass que indica que **a** es un tipo concreto (como Int o Float) que cumple con ese contrato, y lo mismo para b y c.Es importante que quede claro que una typeclass **no es un tipo concreto**, sino una restriccin sobre una variable de tipo (que puede tomar como valores posibles por ejemplo Int o Float, que s son tipos concretos).# Las typeclasses de Haskell ms usadas## Num, Ord y EqNos gustara poder definir los siguientes tipos (a.k.a dominios e imgenes)(+) :: (Si asumimos que a es **numrico**) entonces a -> a -> a(>) :: (Si asumimos que a es **ordenable**) entonces a -> a -> Bool(==) :: (Si asumimos que a es **equiparable**) entonces a -> a -> BoolEn Haskell eso se escribe de la siguiente manera```Haskell(+) :: (Num a) => a - > a -> a(>) :: (Ord a) => a - > a -> Bool(==) :: (Eq a) => a - > a -> Bool```Num, Ord y Eq son **restricciones de tipo**, en Haskell se las conoce como Typeclasses (no confundan esto con el trmino Clase que usamos en el paradigma de objetos!!)En cada Typeclass se definen un conjunto de funciones que los tipos pertenecientes deben implementar. A continuacin mostramos algunos ejemplo de funciones que se definen en Num, Ord y Eq.```HaskellNum a:(+), (-), (*) :: a -> a -> anegate, abs, signum :: a -> aetc.Ord a:(=), (>) :: a -> a -> Boolmax, min :: a -> a -> aetc.Eq a:(==) :: a -> a -> Bool(/=) :: a -> a -> Bool```Veamos cmo impacta esto en la definicin de algunas funciones de listas por ejemplo:```Haskellelem :: (Eq a) => a -> [ a ] -> Boolelem unElemento unaLista = any (unElemento==) unaListamaximum :: (Ord a) => [a] -> amaximum lista = foldl1 max lista```Lo que nos interesa ms que nada es que se note que gracias a que existen las typeclasses que explicitan cul es el conjunto mnimo de funciones que el tipo concreto debe definir para formar parte de ella, luego podemos construir otras cosas encima usando esas funciones y vamos a poder sacarle el mismo provecho. Las funciones `elem` y `maximum` van a funcionar tanto para &#92;[Int&#92;] como para &#92;[Char&#92;] (o sea, para strings).### Qu tipos pertenecen a cada restriccin?Num: Los tipos concretos ms comunes que integran esta familia son Int y Float.Ord: Adems de inclur a la mayora de los tipos numricos (como Int y Float) incluye a los caracteres, los booleanos (s, hay un orden preestablecido para los booleanos aunque no sea comn usarlo). Tambin incluye a las listas y las tuplas siempre y cuando los tipos que las compongan sean ordenables (por ejemplo los Strings, que son listas de caracteres, son ordenables). Las funciones **no son ordenables**.Eq: Todos los Ord y los Num son tambin esquiparables. Para las listas y tuplas, son equiparables si los tipos que las componen lo son. Las funciones **no son equiparables**.Y los data? Algo muy comn es que querramos que nuestros tipos de datos sean equiparables. Si los tipos de datos que componen a nuestros data lo son, alcanza con derivar Eq y no necesitaremos definir la igualdad. De lo contrario, para que sea Eq ser necesario dar un pasito ms avanzado y declarar que nuestro tipo de dato es instancia de la typeclass Eq e incluir una definicin para la funcin (==) como se explica en el artculo sobre [data](data--definiendo-nuestros-tipos-en-haskell.html).Tambin es muy comn querer que nuestros datos se puedan mostrar, y para eso existe otra typeclass que es## La restriccin ShowCuando utilizamos el intrprete, los resultados de nuestras funciones son valores (valores simples, compuestos o funciones), para que se puedan mostrar por pantalla esos valores tienen que tener una representacin en forma de cadena de caracteres (String).La magia la realiza una funcin llamada show```Haskell> show 3"3"> show True"True"> show (2,3)"(2,3)"```Ahora bien, no todos los valores pueden ser parmetro de la funcin show. Por ejemplo las funciones no tienen una representacin en String```Haskell> show lengthError```Debido a esto, cuando quieren mostrar por pantalla una lista de funciones (ej &#92;[fst,snd&#92;]), una funcin parcialmente aplicada como (3+), o en general una funcin que retorna una funcin les va a tirar un error.Veamos el tipo de la funcin show```Haskellshow :: (Show a) => a -> String```La nica funcin que se define en la restriccin Show es la funcin showQu tipos pertenecen a la restriccin Show? Bool, Char, Double, Float, Int, Integer, (Show a) => &#92;[ a &#92;] --Listas, (Show a,b) => (a,b) --TuplasResumiendo: casi todos todos los tipos menos el tipo funcinAl igual que se mencion anteriormente para Eq, podemos hacer que un tipo de dato propio pueda ser mostrado con la funcin Show ya sea usando **deriving** si slo se compone de otros datos de tipo Show o haciendo que sea instancia de Show y definiendo la funcin Show como querramos.# Para cerrar: El truco detrs de la magiaLas typeclasses se pueden traducir/reescribir a un lenguaje sin typeclasses. Y por lo tanto, como pueden reutilizarse los mecanismos de inferencia de tipos de uno para el otro.Para esta traduccin, se usar la metfora de un method dictionary. Cada tipo va a tener un diccionario con sus funciones sobrecargadas. Luego, cada funcin con *polimorfismo paramtrico*, recibe como parmetro el method dictionary y usa la funcin adecuada:Ejemplo:`squarex=x*x`se transforma en algo como```Haskell--ambosdiccionariossondelmismotipo(queeseltipodefinidoenlatypeclass;))dictInt=...dictFloat=....multidict=dict!!1--suponiendoquelafuncinmultiplicacinestaeneldiccionarioenlaposicin1squaredictx=multidictxx```Y cuando ejecutamos`square3`se traduce, como 3 es un Int, en algo como`squaredictInt3`Alguien que ya tiene conocimientos sobre el [paradigma orientado a objetos](paradigma-de-objetos.html) podra encontrar similitudes con el polimorfismo de ese paradigma desde el punto de vista del uso, pero la realidad es que hay magia en el medio a nivel compilador de modo que siempre se sabe qu definicin de funcin se usar en tiempo de compilacin (no se hace un dispatch dinmico)." + +} , + +{ + +"title" : "Typedefs y tipos anonimos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/typedefs-y-tipos-anonimos.html", +"date" : "", +"content" : "# Descripcin*typedef* es una construccin del lenguaje C que nos permite darle alias a tipos existentes (sinnimos de tipos), de forma similar al *type* de Haskell.Esto es particularmente til a la hora de trabajar en ANSI C con estructuras. Por ejemplo, si definimos una estructura TanqueDeAgua de la siguiente forma:```CstructTanqueDeAgua{intcapacidad_maxima;inttemperatura_del_agua;//etc}```cada vez que querramos utilizar este tipo deberemos escribir:```CstructTanqueDeAguaun_tanque;```Lo cual es ciertamente verborrgico, y nos acopla mucho ms a la implementacin: cuando hablo de un tanque de agua, no me interesa si es un *struct*, un *union* u otra cosa.La solucin a este problema es usar un sinnimo de tipo:```Ctypedefstruct_TanqueDeAgua{intcapacidad_maxima;inttemperatura_del_agua;//etc}TanqueDeAgua```Es decir, *TanqueDeAgua* es ahora un sinnimo para *struct TanqueDeAgua*, con lo que puedo escribirTanqueDeAguaun_tanque.De hecho, dado que siempre referiremos a este tipo a travs de su sinnimo, no es necesario darle un nombre a la estructura &#92;_TanqueDeAgua, ya que podemos definir una estructura annima:```Ctypedefstruct{intcapacidad_maxima;inttemperatura_del_agua;//etc}TanqueDeAgua```" + +} , + +{ + +"title" : "Integracion de la ui en una arquitectura de un sistema de software", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-arquitectura-general.html", +"date" : "", +"content" : "# Arquitectura usual de una aplicacin de softwarePara generar una aplicacin, podemos dividir lgicamente los componentes segn el rol que juegan dentro del sistema en s mismo:- **Presentacin**: son elementos que trabajan con la [interfaz de usuario](ui-definiciones-iniciales.html#tocAnchor-1-1), dependientes de la tecnologa- **[Dominio](ui-definiciones-iniciales.html#tocAnchor-1-2)**: son las abstracciones que tienen significado para el que conoce el negocio (una factura, un alumno, un proveedor, una encuesta de satisfaccin de servicio, etc.)- **Persistencia**: son elementos que trabajan en almacenar y recuperar la informacin del sistema en un medio que persista en el tiempo (que no sea voltil).# Formas de divisin de responsabilidades entre cada una de esas partesEsta divisin de responsabilidades se suele denotar como **capas** de una aplicacin. Aqu preferimos utilizar el trmino **concern** o al menos aclarar que la divisin no implica separacin fsica de los componentes. La clasificacin en presentacin, dominio y persistencia tiene que ver con el objetivo que cumple cada componente dentro de la aplicacin.# Interaccin entre la UI y el dominio del sistemaUna idea bastante instalada en el mercado es abstraer la presentacin del dominio tanto como sea posible. De hecho algunos piensan que lo mejor es que no se conozcan/ni se hablen.Entonces la presentacin habla con un objeto intermedio que no tiene comportamiento, solo alguno de los atributos a los que se accede mediante getters y setters. Como la caracterstica de estos objetos es transferir informacion del dominio a la vista se los denomina **Data Transfer Objects o DTO**.Un ejemplo podra ser: en la actualizacin de un empleado se ingresan nombre, apellido, DNI, fecha de ingreso y cargo. En lugar de que la vista conozca a un objeto Empleado que tenga mtodos de negocio (por ejemplo que calcule la antigedad, que sepa cunto cobra, que conteste cuntas horas trabaj un mes, etc.) generamos un EmpleadoDTO, que tiene solamente nombre, apellido, DNI, sueldo mensual en base al cargo y antigedad, stos ltimos dos atributos calculados. El EmpleadoDTO no sabe calcular su antigedad, ni tiene relacin con otros objetos. Esta tcnica puede ser til cuando estamos trabajando en ambientes distribuidos, es decir, en muchas VM que necesito sincronizar.**Pero al separar la presentacin y el negocio de esta manera poco feliz estoy metiendo una solucin que para comunicar dos ambientes OO descarta las principales ideas del paradigma** (el objeto como un ente que agrupa atributos y comportamiento). Incluso es un problema porque tenemos varios objetos que estn representando a un empleado:- el Empleado- el EmpleadoDTOEn definitiva pareciera que la vista no se mezcla con el negocio pero el [acoplamiento](conceptos-basicos-del-diseno.html#tocAnchor-1-5) es claro: para saber cundo fue la ltima vez que le pagu el sueldo necesito:1. generar un nuevo mtodo de negocio si no lo tengo, pero tambin2. agregar un atributo al EmpleadoConsultaDTO para que la vista lo pueda mostrarNuestra idea es que la presentacin no solo hable con el dominio sino que le pida todo lo que le tenga que pedir: en el ejemplo anterior sera muy bueno que la vista le pregunte directamente al empleado cul fue la ltima vez que le pagu.# Links relacionados- [Temario Algoritmos III](algo3-temario.html)" + +} , + +{ + +"title" : "Clasificacion de las UI", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-clasificacion.html", +"date" : "", +"content" : "# Concepto de cliente y servidorUna aplicacin puede pensarse desde la ptica del- **cliente**: el que realiza pedidos- **servidor**: el que responde a esos pedidosLa separacin puede ser:- lgica: ambos componentes residen en la misma mquina- lgica y fsica: adems de pensarse como componentes separados el usuario utiliza un cliente en su mquina y accede al servidor que concentra esos pedidos y se encarga de responderlos.Qu tipo de pedidos hace el cliente? Esto depende de la arquitectura sobre la cual trabajemos:# Arquitectura de las UI1. Aplicacin centralizada2. Aplicacin distribuida (Cliente/Servidor)## Aplicacin centralizada![centralizada](/img/wiki/centralized-application.png)El cliente tiene poca o nula inteligencia. El servidor tiene muchas responsabilidades, esto es:- recibe los parmetros del cliente, los valida y los transforma- procesa las acciones de negocio- transforma los resultados de esas acciones y- genera la visualizacin que va a obtener el cliente como respuesta.Del lado del cliente casi no hay lgica, ni de presentacin ni de negocio, es una "terminal boba". Es el modelo que siguen las arquitecturas mainframe y la web en sus orgenes, donde el browser solo tena capacidades de mostrar la informacin y los controles que el servidor le enviaba.## Cliente / Servidor - Aplicaciones distribuidas![centralizada](/img/wiki/rich_client_application.jpg)En este tipo de aplicaciones, se asume que- los clientes tienen ms capacidad de procesamiento, por lo tanto suelen presentar una interfaz de usuario ms "rica" que las aplicaciones centralizadas (por eso tambin se las suele llamar RIA o _Rich Internet Applications_)- la comunicacin hacia el servidor suele ser un cuello de botella, as que se trata de minimizar la cantidad de informacin a pasar entre cliente y servidor. Por lo general el cliente hace un pedido, la consulta se procesa en el servidor y vuelve la informacin procesada para que el cliente la presente en un formato amigable.- las aplicaciones distribuidas son ms complejas arquitecturalmente: se dividen en 2, 3 hasta _n_ niveles## Peer to PeerOtra alternativa consiste en la red [peer-to-peer (P2P)](https://en.wikipedia.org/wiki/Peer-to-peer), donde cada equipo acta como cliente o servidor dependiendo de si hace un pedido o lo responde (consumer/producer). No existe el servidor como equipo de sincronizacin, sino que cada equipo mantiene su propio estado:![peer-to-peer](/img/wiki/peer-to-peer.png)Ejemplos de aplicaciones peer to peer son Skype, eMule, Torrent, entre otras.## Anlisis comparativo P2P vs. C/S### Ventajas de la visin Cliente/Servidor- **Centralizacin del control**: los accesos, recursos y la integridad de los datos son controlados por el servidor de forma que un programa cliente defectuoso o no autorizado no pueda daar el sistema. Esta centralizacin tambin facilita la tarea de poner al da datos u otros recursos (mejor que en las redes P2P).- **Escalabilidad**: se puede aumentar la capacidad de clientes y servidores por separado. Cualquier elemento puede ser aumentado (o mejorado) en cualquier momento, o se pueden aadir nuevos nodos a la red (clientes y/o servidores).- Dado que hay una cierta independencia entre clientes y servidores, es posible reemplazar, reparar, actualizar o trasladar alguno de ellos con un bajo impacto, siempre y cuando ciertas variables se mantengan estables (debe estar un servidor activo, hay que asegurar el enlace entre los nodos, etc.)- Hay muchas ms tecnologas desarrolladas para el paradigma de C/S.### Ventajas de la visin Peer to Peer- La **congestin del trfico** ha sido siempre un problema en el paradigma de C/S. Cuando una gran cantidad de clientes envan peticiones simultaneas al mismo servidor, puede ser que cause muchos problemas para ste (a mayor nmero de clientes, ms problemas para el servidor). Al contrario, en las redes P2P como cada nodo en la red hace tambin de servidor, cuanto ms nodos hay, mejor es el ancho de banda que se tiene.- El paradigma de C/S clsico no tiene la **robustez** de una red P2P. Cuando un servidor est cado, las peticiones de los clientes no pueden ser satisfechas. En la mayor parte de redes P2P, los recursos estn generalmente distribuidos en varios nodos de la red. Aunque algunos salgan o abandonen la descarga; otros pueden todava acabar de descargar consiguiendo datos del resto de los nodos en la red.- El software y el hardware de un servidor son generalmente muy determinantes: se necesita un buen "fierro" para que un servidor de soporte a una gran cantidad de clientes.- El cliente no dispone de los recursos que puedan existir en el servidor y viceversa. Por ejemplo, una aplicacin que ejecuta en el servidor no puede escribir en el disco local del cliente.# Interfaces orientadas a caracter y grficas- **Orientadas a caracter**: las consolas de configuracin de routers, o las consolas de administracin de herramientas como git, Maven o Travis, el intrprete de comandos de los sistemas operativos, el sistema de reserva de vuelos que trabaja con comandos especficos vs.- **las interfaces grficas**: las que vamos a trabajar mayoritariamente a lo largo de la materia. Qu caractersticas tienen las interfaces orientadas a caracter?- son menos intuitivas, requiere memorizar comandos y cdigos internos - por esto se tarda ms en aprender las operaciones que con las interfaces grficas- una vez pasada la curva de aprendizaje los usuarios expertos trabajan mucho ms velozmente que en la modalidad grfica# Links relacionados- [Temario Algoritmos III](algo3-temario.html)- [Magic Ink - Information Software and the graphical interface](http://worrydream.com/MagicInk/)" + +} , + +{ + +"title" : "Definiciones iniciales de ui", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-definiciones-iniciales.html", +"date" : "", +"content" : "# Interfaz de usuarioEs todo lo que permite a un usuario interactuar con el sistema. Una interfaz se implementa por lo general con una pantalla, pero no es el nico dispositivo posible.Es todo lo que permite a un usuario interactuar con el sistema: esto incluye componentes lgicos (software) y fsicos (hardware). Interfaz de Usuario tambin se puede abreviar por sus siglas en ingls: [**UI (User Interface)**](https://en.wikipedia.org/wiki/User_interface) y en general se suele hablar de la interfaz grfica como la parte de **presentacin** de una aplicacin.# Objetivo de una materia que ensea UINaturalmente, el objetivo de la materia es aprender a programar y disear interfaces de usuario. Sin embargo, la construccin de interfaces de usuario presenta muchos aspectos distintos y por eso conviene entender en cules vamos a hacer foco.## Diseo grfico y diseo de sistemasEn primer lugar, cuando decimos "diseo", nos referimos tanto al diseo de software como al diseo grfico:- el diseo de sistemas se preocupa por distribuir correctamente las responsabilidades de los componentes que forman una aplicacin, para lo cual necesitamos aplicar los conceptos y patrones de diseo que previamente incorporamos- el diseo grfico de una aplicacin trabaja la disposicin del contenido, la eleccin de colores (principal, secundario, de fondo, etc.), la iconografa, logos, imgenes, la _usabilidad_ de manera que sea cmoda e intuitiva para el usuario y ofrezca un mnimo de resistencia o de adaptacin.Si bien una materia del mbito de las TIC est ms relacionada con el primer punto, no es menor la preponderancia que adquiere ltimamente el diseo grfico, ya sea porque es una responsabilidad directamente delegada a quien construye la UI o bien constituye una actividad interdisciplinaria con un especialista.Nuestro objetivo tambin es concentrarnos en producir aplicaciones que se destaquen por sus cualidades de mantenibilidad, flexibilidad, claridad, robustez, entre otras. En el mbito especfico de las interfaces de usuario, un criterio importante ser separar la responsabilidad correspondiente a la interfaz de usuario de la lgica de dominio. Repasemos entonces de qu hablamos cuando hablamos de "dominio" o "negocio".# Modelo de dominioCuando le pedimos al sistema que haga algo, hay reglas que rigen el negocio que manejamos.Si el cliente slo puede pagar con cheque a 30/60/90 das, hay una regla de negocio que lo dice. Si un alumno no puede anotarse en un final porque debe una correlativa, hay otra regla de negocio que lo dice. Si un empleado cobra un 10% del sueldo bsico por presentismo, hay otra regla de negocio que lo dice.Lo que forma parte del dominio de mi aplicacin es encontrar- un cliente que tenga un mtodo``` javapublic void pagar(TipoPago tipoPago, BigDecimal monto)```donde se resuelva esa responsabilidad- un alumno que tenga un mtodo``` javapublic void inscribirseAFinal(Materia materia)```donde se resuelva esa responsabilidad- etc.O sea,- si programamos con objetos, el modelo de dominio se compone de objetos con responsabilidades y relaciones que permiten definir los casos de uso del negocio.- si programamos en otro paradigma, el modelo de dominio sern las entidades + los procesos que resuelven las cosas que necesito para la aplicacin.## Complejidades del dominio y de la UIPongamos por caso esta interfaz conocida de Twitter:![twitter](/img/wiki/ui-twitter.gif)El caso de uso "Twittear" parecera no tener una UI tan compleja, aun as, la pgina chequea todo el tiempo la cantidad de caracteres que escribo y en una forma grfica est mostrando el estado de mi tweet, e incluso debe deshabilitar el botn de "Enviar tweet" si excedo el mximo permitido.Por otra parte, una vez validado, el mensaje que recibe el negocio es algo como:```javatwitter.agregarTweet(nuevoTweet)```que debera incorporar ese nuevo tweet a la coleccin (la persistencia requiere de un objeto arquitectural que normalmente est fuera del alcance del objeto de dominio).En general, la lgica de la presentacin **suele ser siempre mucho ms compleja** que la del negocio, aun cuando el negocio pueda (y debera) ayudar a la UI a agregar funcionalidades que mejoren la experiencia de usuario. > **Corolario**: no es verdad que si el dominio est bien construido la presentacin se hace sola, y la implementacin de la presentacin debera estar a cargo de la gente con ms experiencia, algo que lamentablemente no siempre sucede# Qu objetivos nos proponemos al programar una interfaz de usuario?Por supuesto que ande, pero adems vamos a priorizar ciertas cualidades de diseo: mantenibilidad, flexibilidad, claridad, robustez, entre otras. En particular **tratar de no mezclar ideas de presentacin con negocio**. O sea, separar la lgica para definir la interaccin con el usuario y la lgica propia del dominio. Por qu?- porque no quiero que mi dominio se vea afectado por cuestiones tecnolgicas.- porque eso me lleva a perder cohesin en los objetos de presentacin, que adems de encargarse de mostrar la informacin tienen que atacar cuestiones de negocio. Entonces en dos pantallas distintas tengo que repetir la misma validacin o el mismo comportamiento.- porque tengo ms restricciones a nivel usuario y tecnolgicos del lado de la UI (es la parte ms compleja y la menos madura, cuesta encontrar buenas abstracciones)Volviendo al ejemplo de Twitter,- saber qu color de fondo mostrar en el texto ==> es responsabilidad de la UI- determinar qu texto est excedido del tamao de un tweet ==> es responsabilidad del dominio- saber la longitud de un tweet ==> es responsabilidad del dominio- saber si un tweet est excedido ==> es responsabilidad del dominio- saber si un tweet est cercano a excederse ==> es responsabilidad del dominio- mostrar un color celeste, amarillo o rojo como indicador de que el tweet tiene el tamao apropiado, est cercano a excederse o definitivamente se excedi ==> es responsabilidad de la UIMantener separados estos _concerns_ facilita el cambio de tecnologas de la UI, el testeo unitario de ese dominio, entre otras cosas.# Conceptos bsicos del diseo- [Cohesin](conceptos-basicos-del-diseno.html#tocAnchor-1-4)- [Acoplamiento](conceptos-basicos-del-diseno.html#tocAnchor-1-5)Dnde interviene el acoplamiento al programar la UI? El componente de UI va a tener que conocer al componente que maneja la lgica de dominio, de otra manera la aplicacin no va a funcionar. Pero tampoco es bueno que la interfaz defina lgica que es propia del cliente, o de la factura, o de un empleado o de un alumno (para ms informacin ver [Interaccin entre la UI y el dominio del sistema](integracion-de-la-ui-en-una-arquitectura-de-un-sistema-de-software.html)). Es cierto que agregar un atributo que el usuario deba visualizar o modificar a travs de la interfaz fuerza inevitablemente a un cambio en la UI, pero cambios en la lgica de negocio no deberan necesariamente afectar la UI. As que otro de nuestros objetivos ser minimizar el acoplamiento, no por ser puristas, sino porque nos traer como beneficio no vernos impactados por cualquier tipo de cambio.# Links relacionados- [Temario Algoritmos III](algo3-temario.html)" + +} , + +{ + +"title" : "Elementos a tener en cuenta al programar ui", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-elementos-a-tener-en-cuenta-al-programar-ui.html", +"date" : "", +"content" : "# ObjetivoAl trabajar con interfaces de usuario, aparecen muchos problemas nuevos que no suelen estar presentes en otro tipo de programas. Con el objetivo de establecer una visin global de la problemtica asociada a una interfaz de usuario, queremos determinar qu cosas deben tenerse en cuenta para producir una interfaz de usuario de calidad.Dividiremos las actividades de una interfaz de usuario en dos grandes grupos. El primero de ellos plantea un modelo de ciclo de interaccin, es decir, el conjunto de actividades que suelen ocurrir en cada **interaccin con el usuario**, en secuencia:- Mostrar al usuario las distintas **acciones que puede realizar** (por ejemplo mediante un men, botones, etc)- Permitir al usuario **iniciar una nueva tarea** o caso de uso.- Permitir al usuario **ingresar informacin** asociada a la tarea que desea realizar.- **Transformar** la informacin ingresada por el usuario al formato en el cual la aplicacin los puede manipular internamente.- Actualizar el modelo de dominio con la informacin recibida.- **Validar** la informacin ingresada por el usuario. Suele haber tres puntos distintos de validacin: - Previa a la transformacin. - Posterior a la transformacin y previa a la actualizacin del modelo. - Luego de actualizado el modelo.- Ejecutar de una **accin de dominio** con la informacin recibida.- Manejar y presentar los **errores** si los hubiera.- Seleccionar la **siguiente vista** que se presentar al usuario y la informacin a mostrar en la nueva vista (por ejemplo, filtrado y/o proyeccin).- **Transformar los resultados** al formato en que pueden ser presentados al usuario.En forma transversal a este circuito bsico se presenta un segundo conjunto de actividades, que no depende de un flujo de interaccin sino que se entremezcla con el primero:- Navegacin de la aplicacin entre las diferentes acciones que permite realizar- Manejo de transacciones, concepto de transaccin desde el punto de vista de la aplicacin- Manejo de la sesin de usuario, es decir, en el contexto de una aplicacin multiusuario, la informacin relativa a la actividad de cada uno de los usuarios- Internacionalizacin- Distintas formas de verificacin# Criterios de calidad## Con respecto a la construccin- Consistencia, robustez.- Simplicidad, claridad.- Desacoplamiento entre dominio y UI- Desacoplamiento entre lgica y tecnologa- Testeabilidad o verificabilidad.## Con respecto a la usabilidad- Claridad- Consistencia.- Riqueza (richness)- Feedback- Perfomance y percepcin de performance.- Intuitividad, autoaprendizaje.# Links relacionados- [Temario Algoritmos III](algo3-temario.html)" + +} , + +{ + +"title" : "Formas de vincular una vista con el modelo de dominio", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-mvcpesado-formas-de-vincular-una-vista-con-el-modelo-de-dominio.html", +"date" : "", +"content" : "# Interacciones entre vista y modeloDado que el objetivo de la interfaz de usuario es permitir la interaccin con el modelo de dominio, cada uno de los elementos que conforman la interfaz de usuario tendr como tarea alguna parte de esta interaccin, ya sea mostrar al usuario una porcin del modelo de dominio, o bien permitirle realizar acciones que lo modifiquen.Una forma simple de ordenar una interfaz de usuario es considerar que cada vista (que puede ser una ventana, una pgina o bien una porcin bien delimitada de una vista ms grande) tiene como responsabilidad interactuar con un nico objeto de dominio. A este objeto de dominio lo denominaremos modelo de la vista.Desde esa premisa bsica podemos imaginar que cada vez que haya un control editable en una vista, ese control estar editando algn atributo del modelo. Luego, las modificaciones que realicemos sobre estos controles editables, de alguna manera debern ser *impactadas* sobre los atributos asociados. Al componente de software que toma la responsabilidad de impactar esos cambios lo denominamos controller.Los mecanismos para trasladar o impactar una modificacin hecha por el usuario sobre cualquier control editable se pueden dividir en dos grandes grupos:- Vinculacin indirecta o manual- Vinculacin directa o automtica (*binding*).# Vinculacin indirectaEn este tipo de estrategias los controles editables de la UI toman la responsabilidad de almacenar los valores que va ingresando el usuario a la espera de un evento que *dispare* la ejecucin de la operacin (en aplicaciones web este evento suele ser el *submit* de un formulario HTTP).Naturalmente, ante esta disociacin, el objeto de dominio asociado no se ve afectado por las acciones del usuario hasta que no se produzca el evento antes mencionado. En el momento que se produce el *submit*, el controller deber tomar la responsabilidad de leer todos los valores del formulario de los controles en los que fueron almacenados y recin ah impactarlos en el modelo de dominio.De esta forma, cualquier validacin o modificacin dinmica de los valores en la vista deber ser realizada sin la intervencin del dominio o bien esperar hasta el momento del submit para poder llevarse a cabo. Esto incluye a muchos de los comportamientos denominados *ricos* de una UI, por ejemplo:- Validaciones realizadas a medida que se cargan los datos en un formulario- Valores que dependen unos de otros (un caso tpico: combos anidados).- Controles que se habilitan o deshabilitan dependiendo de los dems valores ingresados.La principal desventaja de este esquema radica en la no-intervencin del modelo de dominio durante la interaccin con el usuario, lo que impide aprovechar toda la lgica que contenga este objeto, que deber tomar uno de dos caminos:- Esperar al momento de submit para intervenir, con lo cual se pierden muchas de las posibilidades de UI *rica* enunciadas en la enumeracin anterior.- Duplicar la lgica ya contenida en el modelo de dominio, replicndola en la interfaz de usuario de forma de poder realizar validaciones y otros comportamientos dinmicos basndose en el contenido de los controles.La primera de las opciones produce una limitacin en las posibilidades que la UI le puede brindar al usuario, hacindolo en muchos casos inviable o en otros perdiendo calidad en la UI. La segunda produce una duplicacin de la lgica que podemos analizar desde dos perspectivas distintas.Por un lado, toda duplicacin de cdigo genera una potencial inconsistencia ante la posibilidad de que una de las dos partes se modifique quedando la otra desactualizada.Por el otro, la lgica propia del dominio metida dentro de la interfaz de usuario resulta mucho ms incmoda de programar ya que deberemos adaptarnos a las restricciones tecnolgicas de componentes que estn diseados prioritariamente para la interaccin con el usuario. Como un ejemplo de las dificultades que aparecen, podemos mencionar que en lugar de tener la informacin necesaria almacenada en variables que tengan un tipo y toda la potencia de nuestro lenguaje de eleccin, deberemos tener los valores contenidos en controles, en muchos casos sin poder exigir que sean de un tipo determinado. Y entonces lo que para nosotros en el dominio es un nmero o una fecha en la UI ser un String o lo que para nosotros es una referencia a otro objeto de dominio en la UI ser un cdigo (String) o un ndice numrico en una lista.Naturalmente todas estas restricciones hacen al cdigo ms complejo y ms propenso a errores, lo que nos lleva a evaluar la siguiente alternativa.# BindingEn este esquema, lo que se buscar es automatizar el pasaje de informacin entre la vista y el dominio. Es decir, se proveer una descripcin ([declarativa](declaratividad.html)) de la vinculacin entre los componentes visuales y el modelo de dominio para que un componente genrico se ocupe de mantenerlos mutuamente sincronizados.A esta descripcin de la vinculacin entre ambos la solemos llamar binding y puede incluir entre otras cosas:- Un mapeo entre un componente visual y un elemento del dominio, tpicamente cada control de la vista estar asociado a un atributo de un objeto de domino.- Conversiones a realizar (por ejemplo si el valor a ingresar es una fecha y se ingresa desde la UI como texto, deber proveerse el formato esperado y la lgica para convertir de ese formato a la representacin interna de fechas que use el modelo de dominio).- Validaciones a realizar (dado que uno de los objetivos es aprovechar la lgica del modelo de dominio, normalmente las validaciones -salvo las propias de la conversin- sern delegadas en el modelo de dominio y por lo tanto la descripcin de la validacin consistir en algn mecanismo para indicar qu consulta realizar sobre el dominio para poder efectuar la validacin en cuestin).Esta estrategia busca fundamentalmente dos objetivos:- Simplificar la sincronizacin entre ambas partes de la aplicacin, basndose en componentes reutilizables.- Aprovechar la lgica contenida en el modelo del dominio para tomar acciones durante su propia edicin.El segundo de estos objetivos es el que suele proponer a veces algunas dificultades, ya que para aprovechar la lgica se necesita impactar las modificaciones realizadas sobre la UI directamente sobre el objeto de dominio. En los casos de aplicaciones que tienen un comportamiento transaccional desde el punto de vista del usuario, esta accin directa sobre el dominio implica algn mecanismo para garantizar que en caso de cancelar la operacin el objeto queda sin cambios, en su estado original antes de comenzar.Adicionalmente esta fuerte vinculacin entre la vista y el dominio nos puede presentar dificultades si la vista tiene requerimientos que no son fcilmente atribuibles a un objeto del dominio, es decir, comportamiento especfico de la vista. Ejemplos de comportamiento propios de la vista podran ser paginar una grilla o dividir la informacin del objeto entre mltiples vietas o *tabs*.Se necesitan entonces herramientas para manejar el nivel de acoplamiento entre la vista y el modelo de dominio, tanto por cuestiones de transaccionalidad como para poder asociar comportamiento no dependiente del dominio.## Binding transaccionalCitamos a continuacin algunos de los mecanismos utilizados para desvincular el dominio de la vista para proveer a nuestra aplicacin de un comportamiento transaccional:### Aprovechamiento de la transaccionalidad de la persistenciaEs frecuente encontrar aplicaciones donde la transaccionalidad est delegada en el mecanismo persistente, con frecuencia una base de datos relacional. Si el modelo de dominio de la aplicacin es persistido en un mecanismo con soporte transaccional y adems el ciclo de vida de los componentes de dominio est dominado por la persistencia (es decir, el objeto de dominio dura en memoria slo durante una transaccin y luego es descartado), entonces simplemente cancelando la transaccin de persistencia se logra descartar los cambios realizados al modelo de dominio. Esta estrategia es muchas veces la ms simple, y si bien tiene algunas limitaciones tcnicas, es una de las ms utilizadas.### Postergacin del binding mediante copias o wrappersEsta estrategia se basa en bindear la vista contra un objeto que no sea exactamente el dominio, para luego volcar los datos sobre el dominio en un paso posterior (probablemente en el submit). Esto permite garantizar que el dominio no se ver modificado hasta finalizar la accin del usuario, al mismo tiempo que trabajar el comportamiento dinmico de la vista sobre un objeto independiente de la tecnologa de presentacin. De esta manera, esta estrategia presenta una alternativa intermedia entre una vinculacin manual y una automtica.Existen dos variantes a esta estrategia. La primera de ellas es utilizar una copia del objeto de dominio a editarse, que luego deber reemplazar al original en el dominio o bien trasvasar la informacin de un objeto a otro. La ventaja de esta estrategia es que permite reutilizar toda la lgica propia del objeto de dominio. El problema es que cuando se editan varios objetos relacionados desde la misma vista, impactar luego los cambios en el dominio puede resultar complejo.La segunda variante es utilizar un wrapper u otro objeto que no sea de la misma clase que el original. Lo interesante de esta tcnica es que provee un mayor desacoplamiento entre vista y modelo (ver *modelo de aplicacin* en el apartado siguiente). La desventaja es que obliga a duplicar la informacin del objeto original en este nuevo objeto (Al menos en un lenguaje basado en clases, en lenguajes con mecanismos de herencia ms flexibles esta problemtica puede ser resuelta de otras maneras, como mixins o traits. Lamentablemente, la mayora de los lenguajes ms populares hoy en da no proveen este tipo de mecanismos.)### Transaccionalidad a nivel de dominio Otra posibilidad es permitir que los objetos de dominio manejen la transaccionalidad, es decir, permitir que sean modificados y, en caso de ser necesario, delegar en ellos mismos la responsabilidad de volver atrs los cambios cancelados por el usuario. Esto puede ser hecho manualmente (aunque puede resultar engorroso) o de forma automtica, por ejemplo mediante aspectos.# Comportamiento a nivel de vistaA veces es necesario tener comportamiento en la vista que no es atribuible a ningn objeto de dominio. En ese caso algunas de las estrategias posibles son:## Modelo de aplicacin Llamamos modelo de aplicacin a un objeto que tiene lgica que no es atribuible a un objeto de dominio, sin embargo es independiente de la tecnologa, por lo tanto podemos considerarlo modelo. Un objeto de estas caractersticas nos provee de un espacio en donde colocar lgica utilizando las mismas herramientas del dominio pero sin tener que restringirnos a las limitaciones que solemos establecer sobre los objetos de domino.Tpicamente los casos de uso complejos de una aplicacin tendrn un modelo de este tipo que contemple la lgica necesaria para llevarlos a cabo. Pueden tener tanto lgica de navegacin como de visualizacin, aunque en algunos casos tambin se decide separar ambos tipos de lgica.## Value Models Otra forma de desacoplar la vista y el modelo es proveyendo un almacenamiento intermedio para cada control, que guarda el valor manejado por el control hasta el momento del submit, en el cual ser volcado al modelo de dominio. Al objeto que contiene el valor durante ese tiempo se lo denomina ValueModel y la principal diferencia con la estrategia anterior es que en ese caso se tena un nico intermediario para toda la vista, mientras que ahora tenemos un intermediario por cada control.Un ValueModel provee de la posibilidad de definir trasnformaciones y validaciones a cada control. Una ventaja importante de este mecanismo es que provee de una forma sencilla de reutilizar la lgica de transformacin y validacin.Por otro lado, la atomizacin de estos objetos dificulta la posibilidad de establecer lgica sobre este modelo que dependa de ms de uno de los controles de la vista.En los casos en que la relacin entre la vista y el modelo de dominio es muy lejana, una solucin posible es descartar el binding y pasar a una estrategia de interaccin manual entre vista y dominio, aunque, claro, eso implica perder parte de las ventajas de automatizar este comportamiento.# Links relacionados- [Ejemplos de Binding entre vista y modelo](ejemplos-de-binding-entre-vista-y-modelo.html)" + +} , + +{ + +"title" : "Intro a MVC", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-mvcpesado-intro-mvc.html", +"date" : "", +"content" : "# Qu necesitamos para construir una UIVamos a armar una lista de cosas que necesitamos para poder desarrollar una aplicacin que tenga interfaz de usuario. Sobre algunas (en negrita) vamos a hablar en este momento, las otras irn apareciendo prximamente:- Elementos grficos / controles / widgets.- Layout o forma de organizar visualmente los widgets.- Binding (de atributos y de acciones).- Navegacin (cmo es el flujo de una vista a otra y cmo se pasa informacin desde una vista a otra).- Manejo del estado conversacional de los datos que se cargan en la vista.# Elementos grficos o widgets (los controles)Podemos clasificar a los controles de la siguiente manera:- container: agrupan otros controles, siguiendo el pattern Composite. Son el formulario, el frame, el groupbox, las solapas, etc. - value holders o los que permiten ingresar un valor: calendars, textbox, checkbox, combo,- radiobutton, etc. - que trabajan sobre conjunto de datos: la grilla, el listbox, treeview (para mostrar - informacin jerrquica), etc.- que disparan acciones: button, link # LayoutCmo disponer esos elementos grficos en la pantalla: ## **layout definido en forma visual**Eso suele generar cdigo por abajo que est pensado en pxeles x@y (un punto) sobre la pantalla. Tener herramientas visuales WYSIWYG nos ayuda a no tener que explicar "quiero el botn ac", armar la pantalla con una toolbar de controles es ms fcil que tener que explicarlo programando, resulta ms intuitivo. Por otra parte lo visual me ata, la mayora de las decisiones que tomo al construir la pantalla no quedan registradas en ningn lado. Yo se que estoy alineando los controles pero no digo en ningn lado alineado a qu porcentaje: es un 40% del ancho de la pantalla? Y... "ms o menos". Si tengo que agregar un campo nuevo a una pantalla con una herramienta visual tengo que volver a acomodar toda la pantalla, tirar para "abajo" los controles que ya estn, volver a respetar el margen, etc. etc.De la misma manera cada vez que me siento a disear una pantalla nueva tengo que tener en cuenta todas estas definiciones que no estn escritas (o pueden estar en un documento que yo me tengo que encargar de respetar: estilos de fuente, disposicin de controles, orden de la botonera: Cancelar primero y Aceptar despus, o al revs, etc.) Esto ocurre aun cuando las herramientas visuales me generen cdigo en Java (o bien generen cdigo propietario que luego se interpreta para armar la parte visual), porque el proceso de creacin de la pantalla queda en la cabeza del que la desarrolla... ## layout definido en forma programticaCuando en lugar de tener una herramienta visual lo codifico me puede pasar lo mismo si no encuentro formas de decir:- "los labels siempre se alinean a la derecha",- "todos los controles de carga de datos del formulario ocupan 70% de la pantalla", - "la botonera se arma siempre: Cancelar, Aceptar y algunos botones configurables", etc. Qu buscamos al definir el layout de la interfaz? 1) que yo no hable en absoluto y trabaje sobre ideas relativas. 2) pero adems, yo tengo que poder decir de alguna manera y en un solo lugar "esto va abajo" , "esto va arriba", "el botn Cancelar va a la izquierda del Aceptar", "todos los botones se agrupan abajo del formulario y centrado", de esa manera es ms fcil despus alinear las botoneras de todas las pantallas a la izquierda, o bien cambiar el layout de la botonera (por ejemplo para que los botones aparezcan a la derecha de la pantalla uno abajo del otro).![image](/img/wiki/thinking_layout.jpg)Lo que est dentro de la nube debera "reificarse" (llevar esa abstraccin al cdigo, esa abstraccin es el Layout).# BindingLo que hace que la pantalla tenga sentido es que los elementos grficos estn relacionados con el dominio. O sea, hay una relacin entre los elementos grficos y los de dominio: muchos elementos grficos son representaciones visuales de elementos de mi dominio,- que pueden mostrar informacin o permitir editarla (la fecha de un alquiler, el nombre de un actor),- o disparar acciones (el alta de un socio, la bsqueda de pelculas segn un criterio, etc.)# Intro a MVCEl binding relaciona parte visual y la informacin que est relacionada. A la primera se la suele llamar vista, a la segunda modelo.El binding se puede dar de dos maneras:- la vista es la nica que actualiza el modelo V > M. Ejemplo: un procesador de texto. Entonces es claro que el flujo va solamente de pantalla a modelo.- la vista actualiza el modelo o el modelo puede actualizarse desde otro contexto y tonces el modelo dispara la notificacin a la vista. V M. La segunda visin (la notificacin en ambos sentidos entre modelo y vista) es la que da sentido a separar modelo de vista para poder reutilizar el modelo en ms de un contexto (ej: si queremos tener una pantalla de Alta de un Socio para un videoclub o bien subir un Excel con un conjunto de socios y que dicha carga sea masiva) Vamos a darle la responsabilidad a alguien (que llamaremos controller) para que se encargue de manejar el binding de atributos y acciones en forma bidireccional (o sea: hacia la vista y hacia el dominio). Para eso vamos a trabajar de la siguiente manera: la vista se va a registrar como interesada en el modelo. Entonces cada vez que alguien actualice el modelo, se va a disparar una notificacin hacia determinados interesados (esta sera una implementacin del Observer pattern).![mvc](/img/wiki/mvc.jpg)En definitiva, si la aplicacin est bien construida lo que pasa es:1. un cambio en la vista dispara un mensaje a un objeto de negocio2. el negocio modifica su estado interno y dispara la notificacin a la vista (en realidad, a todos los interesados, la vista es slo uno ms)3. la vista se actualiza con la informacin del objeto de negocio (esto puede significar que ahora un campo est deshabilitado o que mostremos el socio en color azul porque ya no debe plata)O sea: vista y negocio estn sincronizados todo el tiempo, cada uno sabe qu tiene que hacer:- el negocio sabe su lgica- la vista sabe cmo mostrar la informacin del negocio.# Links relacionados- [Temario Algoritmos III](algo3-temario.html)" + +} , + +{ + +"title" : "Application model. Extendiendo el MVC.", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-mvcpesado-mmvc.html", +"date" : "", +"content" : "# IntroduccinEn Arena cada vista requiere un modelo. Esto implica encontrar una abstraccin que pueda cumplir esa responsabilidad. Algunas pantallas como el conversor de millas a kilmetros utilizan un objeto de dominio como modelo; pero cuando la complejidad de la interaccin con el usuario crece, no nos alcanza con tratar de resolverlo con un objeto de dominio como Celular, Socio o Pelcula.Entonces nuestro objetivo es tener un objeto que sea totalmente independiente de la tecnologa, pero que tenga todo el comportamiento necesario de la aplicacin. Es la representacin del comportamiento global de la aplicacin sin la componente tecnolgica.# Algunos ejemplosUna pantalla de bsqueda de clientes de una compaa que vende celulares:![image](/img/wiki/mmvc-ejemplo1.png)Una ventana para crear un pedido, que selecciona cliente y producto (y tambin permite darlos de alta):![image](/img/wiki/mmvc-ejemplo2.png)E incluso podemos pensar que una pantalla de alta o edicin puede manejarse con un application model, esto permite no tener una referencia extra para conocer al home o repositorio:# ObjetivoConsideramos importante la separacin entre los componentes de la aplicacin que dependen de la tecnologa (vista, controller) y los que no (modelos de aplicacin o de dominio). Y el application model nos da la herramienta para lograr eso.Esta estrategia nos permite:- Tener un modelo rico, en el cual poder programar y disear libremente, sin dependencias tecnolgicas.- Por ser independientes de la vista pueden ser testeados unitariamente con herramientas sencillas (las que ya conocen, sin la complejidad de las herramientas de testeo automtico para interfaces de usuario, vean para eso los tests del ejemplo de los celulares).- Por adaptarse a las necesidades de la vista, simplifican el mapeo que realizan los controllers.El application model funciona como buffer entre la vista y el modelo de dominio y nos va a permitir construir esa parte de la aplicacin programando con objetos y en nuestro lenguaje de preferencia, en lugar de tener que adaptarse a un framework, tecnologa o lenguaje que no tiene la misma potencia. Algunas variantes de ese concepto se pueden ver en el artculo [formas de vincular una vista con el modelo de dominio](ui-mvcpesado-formas-de-vincular-una-vista-con-el-modelo-de-dominio.html).# Objeto de dominio vs. application modelPodemos encontrar dos diferencias importantes:- El application model tiene otra naturaleza en cuanto a la forma en que aparece, no est (a priori) entre los conceptos que maneja el usuario.- Tiene otro ciclo de vida. Los objetos del dominio se crean, se guardan (utilizando probablemente un repositorio persistente), luego se pueden consultar, modificar, etc. En cambio los objetos de aplicacin se usan una sola vez, suelen tener el estado conversacional entre un usuario y la aplicacin, representan un caso de uso.# Esquema MMVCEl objeto Application Model da origen al esquema MMVC [1]:- V - Vista: la pantalla `*Window`- C - Controller: adapta la vista con el modelo, en el caso de Arena son muchos objetos con responsabilidades bien definidas que se relacionan con el application model: binders, transformers, filters, etc.- M - Modelo de la vista/modelo de aplicacin/application model: modela al caso de uso, mantiene simple el binding con la vista- M - Modelo de dominio![image](/img/wiki/mmvc-grafico.png)" + +} , + +{ + +"title" : "Navegación", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-mvcpesado-navegacion.html", +"date" : "", +"content" : "# IntroduccinLa navegacin es un subconcepto de una incumbencia ms general de nuestra aplicacin, y en particular de nuestra interfaz de usuario: la **interaccin**. Toda accin del usuario sobre la interfaz es una interaccin. Navegacin se refiere en particular a esas interacciones que el usuario realizar para poder llevar acabo diferentes **tareas**. En general sern todas las interacciones relacionadas con el ciclo de vida de una **tarea**:- cmo **iniciar** una tarea- cmo **terminar** una tarea: - exitsamente - cancelndola- ser posible realizar tareas **en simultneo**?- podr el usuario **anidar tareas** (realizar una subtarea mientras an sigue con la tarea ms general)?Cmo vern aqu, tanto nombrar el concepto de tarea les dar la idea de que es un concepto importante, ya que la navegacin se define en base a ella. Pero entonces bajmoslo a algo concreto, qu sera una tarea?# Tarea / Caso de usoNos referimos a tarea aqu como una unidad de trabajo que comienza y realiza un usuario sobre el dominio.Por ejemplo, en un sistema de gestin de un videoclub:- Crear un nuevo usuario- Alquilar una pelcula- Buscar un usuario- Eliminar un usuario- Crear una nueva pelcula- Buscar una pelcula- etc.Esta definicin tiene cierta similitud con la idea de caso de uso del anlisis de requerimientos. Por eso a veces se utilizan ambos trminos intercambiablemente.Pero entonces, cmo se relacionan las tareas con la UI?# Relacin entre una tarea y los elementos de UILa relacin entre las tareas y la UI es justamente la navegacin. Esta navegacin, o su implementacin va a depender de varios factores:- La arquitectura: por ejemplo, - Aplicacin standalone de escritorio - Aplicacin web distribuida - Aplicacin mvil distribuida- Los dispositivos: - PC - Handhelds: PDA, Palm - Mobile: android - Dispositivos dedicados o de ciertas industrias particulares- La tecnologa que estemos usando: lase el framework que estemos usando. Las capacidades que nos brinde y sus limitaciones. Por ejemplo, Arena no les permite acceder a los controles propiamente dichos (ejemplo, acceder al texto actual de un TextBox, o a su propiedad `borderWith`).- Los requerimientos de usuario: - La interfaz de usuario es un elemento ms de nuestro sistema, y como todo el usuario/cliente puede tener una idea preconcebida de lo que quiere de ella. De hecho, la interfaz es uno de los puntos centrales ya que es justamente la cara visible para el usuario.As como hemos visto previamente cmo vincular nuestro dominio con la interfaz de usuario (a travs de bindings, por citar un ejemplo), la manera de implementar una **tarea** y su **navegacin** va a depender de todos estos factores que nombramos.# Un ejemplo concretoSi estamos en una aplicacin de facturacin minorista de cualquier negocio, pensemos la vista del caso de uso "Crear factura", y en particular cmo sera la navegacin para seleccionar al cliente. Tenemos varias opciones:- el cliente se selecciona en un campo de autocompletado. El usuario no necesita salir de la pgina.- el cliente se selecciona navegando una bsqueda por diferentes criterios, lo que implica ir hacia una vista nueva (una ventana de dilogo).- adicionalmente, qu estrategia adoptamos si se trata de un cliente nuevo? necesitamos salir de la vista "Crear factura" y navegar a la vista del caso de uso "Crear cliente" o podemos cargar datos mnimos del cliente sin tener que perder el foco en lo que venimos haciendo? la vista que carga el cliente est como una ventana de dilogo o est embebida en el caso de uso actual?# Links relacionados- [Temario Algoritmos III](algo3-temario.html)" + +} , + +{ + +"title" : "Arena. Manejo de transacciones.", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-mvcpesado-transaccion.html", +"date" : "", +"content" : "# IntroduccinSi estamos modificando los datos de una entidad, es frecuente hacerlo en un formulario que tiene dos acciones posibles: aceptar o cancelar los cambios.![edicion-1](/img/wiki/arena_transaction.png)Cuando la UI tiene binding, cualquier modificacin que haga el usuario impacta directamente en el modelo. Qu alternativa tenemos entonces para volver atrs los cambios si el usuario desiste la accin?# Sincronizacin mediante repositorios persistentesSi estamos en un esquema distribuido, una opcin puede ser que nuestro repositorio trabaje con un **medio persistente**, con dos objetivos:- sincronizar la informacin de las distintas sesiones de usuario- proveer un ambiente donde las operaciones son transaccionales (todas las actualizaciones ocurren al mismo tiempo o si falla alguna se cancelan las restantes)En ese caso cuando el usuario presiona el botn Aceptar se enva un mensaje al repo para que actualice el objeto del formulario, caso contrario el repo no recibir ninguna notificacin. Cuando un usuario en otra VM diferente quiere actualizar el mismo cliente, el objeto repositorio toma la informacin del medio persistente para recrear los datos del cliente actualizados. El medio persistente acta como "la nica fuente de verdad", y mientras que los objetos que estn en el ambiente son simplemente un _buffer_ o estado temporal antes de ser almacenados en el medio.![two_users](/img/wiki/arena_transactions_2.png)# Trabajo en una nica VM con bindingSi en nuestra aplicacin el repositorio considera la VM de objetos como la _single source of truth_, el mecanismo de binding puede traer efectos colaterales: **cada vez que el usuario modifique el nombre, eso tiene un impacto inmediato en el modelo** y tenemos que pensar qu debemos hacer si el usuario quiere cancelar la operacin de edicin para que efectivamente se deshagan los cambios.![single_vm](/img/wiki/arena_transactions_3.png)## Opcin 1: Manejo manual de los cambiosLa primera alternativa consiste en generar una copia del objeto original y asociarlo como modelo de nuestra ventana de modificacin.- al cancelar no necesitamos hacer nada, porque los cambios se hicieron contra un objeto que no est asociado al repositorio- al aceptar, pisamos el objeto original (referenciado desde el repositorio) con los nuevos atributos del objeto copia.![copy](/img/wiki/arena_transactions_4.png)## Opcin 2: Elementos transaccionales de ArenaArena propone un esquema para no tener que resolver esto manualmente:- todos los objetos que sean modelos de una vista se anotan como `@Transactional`, para indicar a Arena que participa dentro de una transacccin. Esto incluye a los objetos de dominio y tambin a los objetos que modelan un caso de uso (que llamamos application model, se explican en el formulario de bsqueda).- como adems queremos que disparen notificaciones a las vistas y dems interesados, debemos mantener la annotation `@Observable`- tambin existe la anotacin `@TransactionalAndObservable` (cualquiera de las dos variantes funciona exactamente igual)- la vista debe heredar de `TransactionalDialog`Y con esto nos alcanza, Arena utiliza la vista para delimitar el alcance de una transaccin: cuando el usuario presiona el botn Aceptar se finaliza (`commit`). En caso de error, o de presionar el botn Cancelar, la transaccin se deshace (`rollback`), y los cambios se pierden.El lector interesado puede consultar [el ejemplo de los celulares](https://github.com/uqbar-project/eg-celulares-ui-arena-xtend) que trabaja automticamente la transaccin.# Links relacionados- [Temario Algoritmos III](algo3-temario.html)" + +} , + +{ + +"title" : "Validaciones y manejo de errores en la UI", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-mvcpesado-validaciones-errores.html", +"date" : "", +"content" : "Podemos ver un repaso del tema excepciones en [esta pgina](excepciones-avanzadas.html)# IntroduccinConsideremos el ejemplo de los clientes de una empresa de celulares, donde tenemos un formulario que permite ingresar- nombre del cliente- nmero de celular- modelo de celular- si quiere recibir el resumen de cuenta en el domicilio# Validaciones a implementar1. El nmero debe contener slo dgitos numricos1. El modelo de celular debe ser un modelo vlido1. Los nmeros de celular deben ser mayores a 10001. No puede ingresarse el mismo nmero de telfono para dos clientes diferentes1. Algunos modelos de celular exigen que sus clientes reciban el resumen de cuenta en su domicilioQu hacemos en cada caso? Quin es responsable de cada validacin?# Momentos de la validacin## El nmero debe contener slo dgitos numricosSi el objeto de dominio Celular define el nmero de telfono como un Integer, no es posible hacer```scalacelular.numero = "A"```eso **no compila**. Pero la UI podra tener un cuadro de texto que permita ingresar caracteres alfanumricos: entonces tenemos que elegir cul va a ser el comportamiento del sistema1. permitir ingresar caracteres invlidos pero mostrar un mensaje de error: en Arena esto lo hace por defecto el controller que adapta lo que el usuario carga a lo que el dominio necesita. El panel de errores (ErrorsPanel) captura cualquier excepcin que ocurra en la conversin, ya sea que lo incluyamos manualmente o por una ventana que herede de `SimpleWindow`.1. podramos pensar: para qu dejamos que el usuario ingrese un caracter invlido si luego lo vamos a rechazar? La segunda variante consiste en definir un filtro que no permita que el usuario pueda ingresar caracteres alfabticos si queremos que ingrese nmeros. Para esto...### Opcin 1: Definimos un filterEsta es la versin en lenguaje Java:```javanew TextBox(form) .withFilter(new TextFilter { public boolean accept(TextInputEvent event) { return StringUtils.isNumeric(event.getPotentialTextResult()); } }) .bindValueToProperty(Celular.NUMERO);```La misma versin en lenguaje Xtend:```scalanew TextBox(form) => [ withFilter [ event | event.potentialTextResult.matches("[0-9,.]*") ] bindValueToProperty("numero") width = 100]```Qu es el TextFilter dentro del MVC? El TextFilter es un **controller**, porque se comunica con el dominio _(le manda un mensaje al modelo - en el caso de estar ok el input)_ y acta sobre la vista _(en la pantalla no aparece ese caracter, se filtra)_.### Opcin 2: Utilizamos un control especfico para ingresar nmerosDesde Arena 3.6.1 tenemos un control NumericField que se encarga de filtrar los caracteres alfabticos:```java// Javanew NumericField(form).setWidth(150).bindValueToProperty("numero");``````scala// Xtendnew NumericField(form) => [ value "numero" width = 100]```Internamente est utilizando un Filter, lo importante es que tenemos una abstraccin de alto nivel que est diciendo "quiero un control donde slo se puedan cargar nmeros".Entonces la primera variante es impedir cualquier ingreso invlido por parte del usuario: Esto tiene como ventaja ser fail fast, evita ingresos incorrectos y esto para el usuario es ms beneficioso.## Otras formas de evitar acciones incorrectasSiguiendo la anterior linea de pensamiento, debera dejar que el usuario presione el botn Aceptar, solo para mostarle un mensaje de error despus? no debera habilitar el botn Aceptar solamente cuando todos los controles se hayan cumplido satisfactoriamente?Aqu vemos que esta estrategia tiene un lmite: en ciertos casos las validaciones del negocio pueden ser verdaderamente complejas como para poder dejarlas en forma explcita en la pantalla. Entonces el usuario sentir una lgica frustracin de no poder avanzar con el caso de uso cuando el botn Aceptar est inhabilitado y no quede claro por qu. **Una regla importante para la usabilidad de un sistema es que debe explicar claramente al usuario qu informacin no cumple las reglas de negocio y adems cmo debe continuar para llegar al caso exitoso**.# Implementando las validaciones restantes## El modelo de celular debe ser un modelo vlidoEl responsable es el celular? s, si lo pensamos como un dato obligatorio, pero claramente participan1. la UI que gua al usuario mostrndole un combo con las opciones vlidas, el usuario no puede elegir un modelo inexistente, a lo sumo puede dejarlo vaco2. si yo permito que el combo quede vaco, el dominio (el objeto celular) debera validar que el celular no deje en blanco el campo modelo. El form builder permite en sus opciones decirle "este combo no tiene la opcin vaca".```java// JavaSelector selector = new Selector(form) // .allowNull(false);``````scala// Xtendnew Selector(form) => [ allowNull(false)```El tema es que al dar de alta un celular el binding es contra un atributo nulo, entonces el combo queda igualmente vaco. Dnde voy a poner la validacin del celular? En la clase Celular, un mtodo validar() qu va a devolver? void, o exception si hubo error... nada de cdigos de error numricos, como saben. Porque si todo sale bien slo sigo enviando mensajes a los objetos que corresponden. Y si algo sale mal se que tengo que atrapar una excepcin en la vista.Entonces no acoplo innecesariamente las validaciones del modelo a la vista. La pantalla de edicin slo tiene que saber que pueden ocurrir dos tipos de error posibles:- **errores de negocio:** surgen de las restricciones que el negocio va poniendo (no pods ingresar un modelo inexistente, no pods poner caracteres alfabticos en la lnea del celular). Esto lo modelamos con una UserException.- **errores de sistema:** son errores propios de la programacin, o errores generales del sistema (algo se rompi). Estos no los modelamos, simplemente ocurren: son los NullPointerException, OutOfMemoryError, etc.Codificamos entonces el mtodo validar:```java// Javapublic void validar() { ... if (this.modeloCelular == null) { throw new UserException("Debe ingresar un modelo de celular"); }}``````scala// Xtenddef void validar() { ... if (modeloCelular == null) { throw new UserException("Debe ingresar un modelo de celular") }}```Quin debe atrapar esta excepcin que tira el negocio? Eso tiene que estar del lado de la tecnologa de presentacin: en la vista o ms precisamente en el controller, all debe estar el bloque try/catch para trabajar tanto los errores de negocio como los de sistema:- si ocurre un error de usuario/negocio, el mensaje contiene informacin importante para el usuario. Entonces hay que mostrarle un cartel (o dejar una parte especfica del panel para mostrar errores) con lo que contenga la propiedad message de la excepcin de usuario/negocio- por el contrario, si el error se da dentro del programa, mostrar el mensaje de error al usuario le genera confusin: lo mejor que uno puede hacer es advertirle al usuario que hubo un error, que la operacin que solicit no va a poder completarse y sobre todo, registrar el problema para que un desarrollador lo analice luego.## Los nmeros de celular deben ser mayores a 1000Si ponemos la validacin en el setter```java// Javapublic void setNumero(Integer numero) { if (numero ` donde T es un Celular (hereda de `Entity`):```javapublic void create(T object) { this.validateCreate(object); ...```Definimos la validacin en RepositorioCelulares:```java// Java@Override public void validateCreate(Celular celular) { celular.validar(); validarClientesDuplicados(celular);}public void validarClientesDuplicados(Celular celular) { int numero = celular.getNumero(); if (!this.search(numero).isEmpty()) { throw new UserException("Ya existe un celular con el nmero: " + numero); }}``````scala// Xtendoverride validateCreate(Celular celular) { celular.validar() validarClientesDuplicados(celular)} def void validarClientesDuplicados(Celular celular) { val numero = celular.numero if (!this.search(numero).isEmpty) { throw new UserException("Ya existe otro cliente con el mismo nmero") }}```Qu pasa en la modificacin?- Actualizar una coleccin en memoria es simplemente borrar el objeto anterior y agregar el objeto editado, eso est definido en CollectionBasedRepo.- Arena no defini un mtodo validateUpdate() para incorporar validaciones. Esta limitacin suele ser comn al utilizar frameworks, eso no evita que podamos interceptar el mensaje update, de la siguiente manera:```scalaoverride update(Celular celular) { validarClientesDuplicados(celular) super.update(celular)}```Al fin y al cabo estamos trabajando con objetos.Y la validacin cundo se dispara? Cuando aceptamos el formulario, porque determinar si el nmero de celular se repite con otro tiene sentido cuando terminamos de definir el nmero, y adems esa operacin tiene un costo.## Obligatoriedad de recibir resumen de cuenta en domicilioCada celular pertenece a un modelo de celular que define si debe recibir el resumen de cuenta en domicilio. Cmo afecta eso a la ventana de edicin?- Una opcin es que la vista no sufra modificaciones: en el mtodo validar chequeamos que el usuario haya cargado una configuracin vlida para el modelo de celular y recepcin de resumen de cuenta en domicilio.- Pero para el usuario esta decisin puede resultar desconcertante: qu modelo ser el que me permita dejar destildado el check? Por eso para disear una buena UI necesitaramos hacer algunas modificaciones: si el modelo de celular obliga a que el cliente reciba el resumen de cuenta, debera - automticamente ponerse en true el flag recibeResumenCuenta para el cliente - deshabilitarse la opcin de modificar el checkEntonces vemos que la validacin original en el celular pierde sentido: la interfaz va guiando al usuario impidiendo que tome decisiones incorrectas y minimizando as las ventanas de error segn las restricciones que impone el negocio. Eso no implica sacar la validacin, pero s tener en mente la famosa experiencia de usuario para anticiparnos a ingresos incorrectos.Aunque no siempre es posible evitar los mensajes de error, como hemos visto con la duplicidad de nmeros de celular (no podemos saberlo sin consultar al repositorio), estas ideas de diseo en la UI mejoran notablemente su usabilidad.# Algunas conclusiones## Desventajas de las excepcionesComo las excepciones cortan el flujo normal de envo de mensajes entre objetos, la contra de tirar una excepcin por cada error de negocio es que no nos permite decirle al usuario todos los campos que tienen problemas (los errores van apareciendo de a uno). Por eso otra tcnica es "recolectar" los errores y asociarlos a campos, de manera de tener un listado de mensajes de error donde cada uno est asociado a un campo que se ingresa en el formulario.## Pop-ups y paneles de errorVolviendo al ejemplo de los celulares, vemos que la validacin tira User Exceptions:```scaladef void validar() { if (!this.ingresoNumero) { throw new UserException("Debe ingresar nmero") } ...}```Lo mismo ocurre con validaciones que hacen los repos:```scalaprivate void validarClientesDuplicados(Celular celular) { val numero = celular.numero if (!this.search(numero).isEmpty) { throw new UserException("Ya existe un celular con el mismo nmero") }}```Pero esa excepcin no est atrapada en el mtodo asociado al botn Aceptar de la pantalla de Edicin.```scalanew Button(actions) .setCaption("Aceptar") .onClick [ | this.accept] .setAsDefault .disableOnError```Cmo es entonces que funciona bien, que los errores se muestran con un popup?- cada control de arena tiene un realidad abajo un builder que crea finalmente los objetos de la tecnologa. En nuestro caso objetos swt + jface- por ejemplo, al crear un SimpleWindow nosotros estamos utilizando (sin saberlo) un JFaceWindowBuilder que le construye el ErrorViewer (esto no ocurre si nuestra ventana hereda de Window solamente)- Cuando se crea un botn, por ejemplo, y le seteamos un Action en el onClick, esta capa de Arena le agrega un listener (un observer) que envuelve el command que nosotros construimos incorporndole el manejo de errores:```java@Overridepublic void widgetSelected(SelectionEvent event) { try { this.action.execute(); } catch (UserException exception) { this.context.getErrorViewer().showWarning(exception.getMessage()); } catch (RuntimeException exception) { exception.printStackTrace(); this.context.getErrorViewer().showError("Se produjo un error de sistema. Puede revisar el log de la aplicacin para obtener ms detalles"); }}```El bloque catch puede variar dependiendo de la versin de Arena que estn usando. Pero ms all de algunos detalles de implementacin que pueden ver ustedes, lo importante es ver qu sucede con los dos tipos de excepcin:- errores de usuario/negocio: mostramos el error en una ventana de dilogo. Qu dice el mensaje de error? A la ventana no le interesa, sabe que cualquier accin que disparemos puede dar este tipo de error, y que el mensaje contiene informacin importante para el usuario. Pero no acoplamos la UI al resto de los componentes del sistema: nos da lo mismo si el nmero de celular debe comenzar con 15, si ya existe otro alumno con el mismo legajo o si no podemos cargar una fecha de nacimiento futura para los empleados.- los errores de programa los catcheamos despus, porque RuntimeException es ms general que UserException. Hay una decisin de diseo de no envolver las excepciones chequeadas, para respetar as a quienes quieran trabajar con este tipo de excepciones.- mientras que la excepcin de programa se "loguea" (haciendo un printStackTrace), las excepciones de negocio no tiene sentido registrarlas. Las excepciones de programa las leen los programadores, las de negocio le sirven al usuario para comprender que est tratando de usar el sistema de manera incorrecta, el mensaje de error le debe aportar una ayuda para solucionar este inconveniente y seguir adelante.- el log default hace un printStackTrace(), esto deja en el archivo standard output la pila de mensajes donde ocurri el error. Este archivo puede ser voluminoso, entonces - se suele particionar los errores por aplicacin (y a veces por mdulo tambin) - tambin se registran datos adicionales, como usuario logueado, fecha y hora en que ocurri el error, esto por lo general se puede parametrizar sin mucho esfuerzo - otra cosa que se suele hacer es activar/desactivar niveles de logueo para ver cmo est funcionando una aplicacin (niveles debug/info/warning/error/fatal) - y el ErrorViewer sabe mostrar un mensaje de error al usuario (showError), en este caso mediante una ventana de dilogo# Links relacionados- [Temario Algoritmos III](algo3-temario.html)" + +} , + +{ + +"title" : "Introducción a la Arquitectura web", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/ui-web-intro-arquitectura.html", +"date" : "", +"content" : "# Arquitectura distribuidaLa arquitectura web trabaja con dos nodos:- el **cliente** tiene un programa ejecutable (application client, el _web browser_ o navegador es el ms comn)- y el **servidor** tiene otro programa ejecutable: en la materia ser nuestro application server el que tendr una VM donde vivan los objetos de negocio.Estos nodos son lgicos: pueden estar ubicados fsicamente en la misma mquina, pero igualmente tendremos una separacin de componentes en cliente y servidor.El cliente hace pedidos a travs de un puerto contra el servidor, el servidor responde. El flujo de mensajes siempre comienza en el cliente:- cliente pide servicio (request)- servidor responde (response)![image](/img/wiki/ui-web-arquitectura.png)## Algunas consecuencias- Nuestra aplicacin pasa a ser una **aplicacin distribuida**: va a tener una parte corriendo en el servidor y otra parte corriendo en el cliente. Dependiendo de la arquitectura que elijamos - podemos tener la mayor parte de la lgica en el servidor y tener un cliente liviano (thin) o ZAC (Zero Administration Client). Entonces lo que le llega al cliente es slo un documento HTML, y es fcil mantener la aplicacin cuando tengo muchos clientes ubicados - o bien podemos poner gran parte de la lgica en el cliente y utilizar la parte server solamente para sincronizar la informacin entre sesiones de usuario- de todas maneras, por ms liviano que sea el cliente, los _browsers_ no son uniformes, entonces si queremos que una aplicacin ande en todos ellos muchas veces vamos a tener que manejar cdigo especfico para cada plataforma (browser, versin, sistema operativo y a veces hasta el hardware).- como el cliente es el que dispara los pedidos, todas las interacciones entre el usuario y la aplicacin deben ser iniciadas por el usuario, la aplicacin no puede tomar la iniciativa. Ej: si tengo una lista de tareas pendientes, para que aparezca una nueva tarea hay que obligar al cliente a que dispare el refresh.## Pedido/respuestaAntes de meternos ms de lleno, nos preguntamos: la tecnologa de objetos es consistente con la metfora "pedido-respuesta" (request/response)? S, en definitiva es la representacin de lo que es un mensaje.Lo que pasa es que en un sistema con objetos no pongo restricciones: cualquiera puede ser emisor y cualquiera receptor. En cambio en la tecnologa web siempre es el cliente el que pide y siempre el servidor el que responde.# Cmo se implementa la comunicacinEl cliente dice: "necesito x". Esto se traduce en una direccin de una pgina en particular, esa direccin recibe el nombre de **URL** (Uniforme Resource Locator, o forma de encontrar un recurso en el servidor):```urlhttp://localhost:8080/html-css/index.html```donde- http es HyperText Transfer Protocol, el **protocolo de comunicacin** por defecto que usan los navegadores - otros protocolos son https (donde los datos viajan encriptados), ftp, etc.- localhost es el **servidor web** hacia el que vamos a conectarnos - en este caso `localhost` es el web server que est en la PC local, que equivale a la direccin IP 127.0.0.1 - el servidor web puede ser una direccin IP o un nombre que luego es convertido a una direccin IP a travs de un DNS (Domain Name Server)- 8080 es el puerto donde el servidor est "escuchando" pedidos- y finalmente la pgina que queremos cargar, que recibe el nombre de **recurso**La forma en que publicaremos las pginas como **rutas** depende de la tecnologa en la que trabajemos y lo veremos ms adelante, lo importante es entender que una pgina html es accesible para un usuario con una ruta nica llamada URL.# HTTP[Http](https://es.wikipedia.org/wiki/Protocolo_de_transferencia_de_hipertexto) es un protocolo **no orientado a conexin** que define la forma de comunicacin entre el cliente y el servidor.Recordemos que no-orientado a conexin significa que no guarda ninguna informacin sobre conexiones anteriores, por lo que no tenemos el concepto de sesin de usuario, es un protocolo sin estado (_stateless protocol_). Esto tiene varias implicancias, la ms fuerte es que requiere que la aplicacin mantenga la informacin necesaria para mantener una sesin (por ejemplo, sabiendo qu usuario es el que est haciendo una operacin).Un mensaje http tiene formato de texto, por lo que es legible al usuario y fcilmente depurable, como vemos en el siguiente video:![video](/img/wiki/ui-web-architecture-http-request.gif)Abrimos en un navegador las herramientas de desarrollo (por lo general es la tecla F12), y en la solapa _Network_ podemos inspeccionar las distintas respuestas que procesa el navegador, con el pedido http original que hace un mensaje de tipo `GET`.## Tipos de mensajeUn cliente puede enviar un pedido al servidor utilizando diferentes mtodos- `GET`: asociada a una operacin de lectura, sin ningn otro efecto- `HEAD`: es exactamente igual al pedido va GET pero enviando nicamente el resultado de la operacin en un header, sin el contenido o _body_- `POST`: se suele asociar a una operacin que tiene efecto colateral, no repetible- `PUT`: est pensado para agregar informacin o modificar una entidad existente- `DELETE`: se asocia con la posibilidad de eliminar un recurso existente- `OPTIONS`: permite ver todos los mtodos que soporta un determinado servidor web- `TRACE`: permite hacer el seguimiento y depuracin de un mensaje http (se agrega informacin de debug)- `CONNECT`: equivalente a un `ping`, permite saber si se tiene acceso a un hostMs adelante volveremos sobre esto al estudiar REST. Ahora veremos la diferencia entre hacer un pedido mediante GET vs. POST.### Envo mediante GET methodAqu los parmetros viajan dentro de la URL como par `clave=valor`: ```urlhttp://www.appdomain.com/users?size=20&page=5```- `?` delimita el primer parmetro- `&` delimita los siguientes parmetrosLa ventaja de utilizar este mtodo es que dado que http es un protocolo no orientado a conexin, podemos reconstruir todo el estado que necesita la pgina a partir de sus parmetros (es fcil navegar hacia atrs o adelante). Por otra parte es el mtodo sugerido para operaciones sin efecto, que recuperan datos de un recurso.Por otra parte, no es conveniente para pasar informacin sensible (como password o ciertos identificadores), algunos navegadores imponen un lmite mximo de caracteres para estos pedidos y necesita codificar los caracteres especiales (p. ej. el espacio a `%20`) dado que el request solamente trabaja con el conjunto de caracteres ASCII.### Envo mediante POST methodLos parmetros viajan en el BODY del mensaje HTML, no se ven en la URL del browser. Aqu no hay restricciones de tamao para pasaje de informacin y tampoco se visualizan los parmetros en la URL del browser.### GET vs. POSTLa [recomendacin W3C](https://www.w3.org/TR/html4/interact/forms.html#submit-format) (World Wide Web Consortium) dice que deberamos usar - GET cuando sepamos que se trata de consultas que no van a tener efecto colateral (no habr modificacin en el estado del sistema)- POST cuando sepamos que el procesamiento de la pgina causar una alteracin del estado del sistema (al registrar el alquiler de una pelcula, al modificar los datos de un socio o al eliminar un producto de la venta). Otros mtodos posibles que veremos son PUT y PATCH, para modificaciones y alteraciones parciales, respectivamente.# El camino de un pedido http- el browser se conecta con el servidor a partir del dominio o IP (localhost = 127.0.0.1) y puerto- se enva la peticin al servidor en base a direccin, mtodo, parmetros, etc.- el servidor responde a ese pedido: esa respuesta es una nueva pgina con un cdigo de estado HTTP: - 200 : OK - 401 : Unauthorized - 403 : Forbidden - 404 : Not Found - 405 : Method not allowed - 500 : Internal Server ErrorEl lector puede buscar la lista de [cdigos de error HTTP](https://es.wikipedia.org/wiki/Anexo:C%C3%B3digos_de_estado_HTTP) (las especificaciones [RFC 2616](https://tools.ietf.org/html/rfc2616) y [RFC 4918](https://tools.ietf.org/html/rfc4918)) y formas de resolverlos.- la aplicacin cliente o _user agent_ se desconecta del servidor una vez procesada la respuesta# Consecuencias del mensaje http para las aplicaciones webLa pgina es la mnima unidad de informacin entre cliente y servidor, lo que implica:- **problemas en la performance**: no siempre debera refrescar toda la pgina si slo necesito actualizar parcialmente la informacin de dicha pgina- **problemas en el diseo**: tengo dificultades para poder particionar una pantalla en componentes visuales- **problemas de usabilidad**: para que la pgina sea dinmica necesitamos forzar una comunicacin con el servidor**String oriented programming**: la comunicacin entre cliente y servidor involucra solo texto, necesitamos adaptar fechas, nmeros, booleanos y tambin los objetos de negocio (socios de un videoclub, alumnos, materias, vehculos de una flota, etc.) as como las colecciones.# Procesamiento de la respuesta en el clienteEl servidor contesta con un string que tiene- un _header_ donde indica el resultado del pedido- un contenido, que forma parte del body, que puede ser HTML, json o cualquier otro formato que el cliente entienda![](/img/wiki/ui-web-architecture-http-response.gif)Arriba vemos la respuesta del navegador al buscar "Cuarteto de Nos" y abajo cmo procesa la consulta el cliente Postman.![](/img/wiki/ui-web-architecture-http-response2.gif)# Resumen- Muchos clientes se conectan a un nico servidor a travs del protocolo HTTP- En el cliente corre un programa llamado _user agent_ que es el encargado de establecer la comunicacin con el web server. Se utiliza el concepto de thin client, es decir que se minimiza la lgica en los clientes, tendiendo a concentrarla en el servidor. **Consecuencias:** - se simplifica la utilizacin de la aplicacin desde mltiples clientes sin costo de instalacin ni mantenimiento. - se simplifica la lgica al mantener toda la aplicacin centralizada.- La descripcin de las pantallas se basa en [HTML](html.html). Es decir, una pgina dinmica es un programa que genera un String conteniendo cdigo HTML.- Progresivamente se ha incrementado la tendencia a describir las cuestiones estticas utilizando [CSS](css.html), por lo tanto la descripcin de una vista estar dada por una combinacin de HTML y CSS.- La comunicacin entre el cliente y el servidor est dada en la forma de pedido-respuesta (request-response).- Todas las interacciones entre el usuario y la aplicacin deben ser iniciadas por el usuario, la aplicacin no puede tomar la iniciativa.- La respuesta para cada pedido es una pgina nueva, la mnima unidad de comunicacin entre el cliente y el servidor es una pgina. Esto tiene consecuencias tanto de performance como de usabilidad y tambin de diseo. Existen muchos tipos de pedido pero los ms usuales son GET y POST. Los dos puntos anteriores limitan gravemente la posibilidad de utilizar mecanismos de binding.- Cada pedido es independiente de los anteriores, es decir, la tecnologa no provee de un soporte directo para manejar el estado de la conversacin entre ambos procesos (**stateless**). Para modelar procesos que requieran de una comunicacin ms poderosa que esa debern proveerse herramientas adicionales, frecuentemente manipuladas ad-hoc.# Links relacionados- [Temario Algoritmos III](algo3-temario.html)- [W3 - Web Architecture](https://www.w3.org/standards/webarch/)- [HTML](html.html)" + +} , + +{ + +"title" : "unexpected", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/unexpected-----.html", +"date" : "", +"content" : "Un error que puede aparecer al programar en haskell es:```scalaERROR[file:.&#92;tp1](file:.&#92;tp1)funcional:6-Syntaxerrorinexpression(unexpected ;',possiblyduetobadlayout)```Pero yo no puse ningn punto y coma! Qu onda?La respuesta corta es que hay que revisar la sintaxis y en particular la *indentacin*. El por qu de ese mensaje tan raro, a continuacin.Indentacin-----------El haskell usa una sintaxis "bidimensional" (no se asusten), eso quiere decir que si vos "indents" algo, eso tiene un significado. Entonces antes de continuar hay que entender el concepto de indentacin. Indentar algo es dejar espacios o tabs adelante del cdigo, generalmente uno lo hace para que se lea mejor, por ejemplo```pascalfunction fact(n: integer): longint; beginif(n=0)thenfact:=1elsefact:=n*fact(n-1);end;```Podemos ver que el programador dej algunos espacios antes de las palabras if y then, entonces visualmente es claro que todo eso queda dentro del bloque definido por begin/end. De la misma manera las lneas de cdigo que estn dentro del if y del else tienen an ms espacios ("ms indentacin").Sintaxis "bidimensional"------------------------Como dijimos, el haskell utiliza una sintaxis bidimensional, es decir, en pascal o c la indentacin son opcionales, no tienen significado, es decir, uno los pone slo para entender mejor el programa; en cambio en haskell no hacen falta los / de pascal ni las llaves de C para demarcar un bloque de cdigo. En haskell un bloque es demarcado directamente con la indentacin.Entonces la funcin que en C se escribira:```cintsuma(inta,intb){returna+b;}```En haskell no necesita de las llaves, porque se da cuenta a partir de la indentacin:```haskellsumaab=a+b```Tampoco son necesarios los tipos ni el return, pero eso es otro tema, lo que nos interesa ac es que no son necesarias las llaves ni el punto y coma, porque con la indentacin y el fin de lnea es suficiente para que el compilador entienda dnde empieza y termina la funcin. (En este caso sera an ms simple poner todo en una sola lnea, pero algunas funciones complejas tienen ms de una lnea.)En resumen, si vos indents mal es anlogo a olvidarse una llave o un o un ';' en otro lenguaje.Por qu entonces dice *unexpected ';*', si yo no puse ningn ';'?------------------------------------------------------------------Se puede entender como que el haskell a partir de la sintaxis bidimensional "completa" los demarcadores de comando y de bloque, de una forma similar al C, quedando algo parecido a:```haskellsumaab={a+b;}```De hecho, es posible escribir la funcin de esa manera si uno prefiere... pasa que obviamente uno prefiere la sintaxis con menos chirimbolos.Entonces, cuando dice "unexpected ';'" lo ms probable es que no est entendiendo el "layout" que ustedes le dieron a al funcin, es decir, la forma en que la indentaron. Ese "bad layout" hace que en su traduccin aparezca un ";" en algn lado que no tiene sentido. Saber dnde est ese ";" no es sencillo, hay que revisar el layout de la funcin.[Ejemplo de problemas de indentacin en Haskell](http://stackoverflow.com/questions/2223468/haskell-where-indentation-why-must-it-be-indented-past-identifier)" + +} , + +{ + +"title" : "Unificacion y pattern matching", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/unificacion-y-pattern-matching.html", +"date" : "", +"content" : "# UnificacinDentro de los conceptos del paradigma lgico no est incluido el concepto de **asignacin**. Para dejar en claro esto vamos a llamar a esta idea **[Asignacin Destructiva](transparencia-referencial--efecto-de-lado-y-asignacion-destructiva.html)**, esto se debe a que una asignacin me permite "destruir" el valor que tiene una variable en un momento dado y reemplazarlo por otro. Esta idea de asignacin no tiene sentido cuando pensamos en incgnitas (si en un momento dado decimos que una variable X vale 1, su valor ser 1 y ningn otro hasta que se empiece a buscar otra solucin a la misma consulta, en ese momento se desligan todas las variables y se empieza de nuevo). Las variables en el paradigma lgico se asemejan a la idea de variable matemtica, y el mecanismo por el cual se le dan valores a las variables se llama **unificacin**. Cuando una variable que no tiene ningn valor pasa a tenerlo vamos a decir que dicha variable a sido **ligada**, en caso contrario la variable se encuentra **sin ligar o no ligada**.Si nuestra base de conocimiento es```prologpadre(homero,bart).padre(homero,maggie).padre(homero,lisa).Y hago la consulta?- padre(X,lisa). X = homero```## Cmo obtuvo ese resultado Prolog?Bsicamente lo que hace Prolog es buscar un **consecuente** (revisar al principio de todo qu era eso de consecuente) dentro de todas las clusulas de nuestra base de conocimiento que unifique con la consulta. Podemos ver un poco la unificacin o falta de unificacin entre dos hechos (que seran la consulta y el consecuente) haciendo consultas en SWI que jueguen con el = (igual), para la consulta de recin tenemos:El consecuente de la primer clusula **NO** unifica con la consulta```prolog?- padre(X,lisa) = padre(homero,bart).No %El consecuente de la segunda clusula **NO** unifica con la consulta?- padre(X,lisa) = padre(homero,maggie).No %El consecuente de la tercer clusula **unifica** con la consulta?- padre(X,lisa) = padre(homero,lisa).X = homero```***OJO*** el = (igual) nooooo lo vamos a usar en los programas, lo usamos ac solamente porque nos ayuda a estudiar sobre la unificacin.Este ejemplo es fcil ya que todas las clusulas son hechos pero **no es nuestra intencin entender en profundidad el mecanismo de unificacin**. Si se tratara de reglas, tiene que pasar que se resuelvan los antecedentes de la clusula cuyo consecuente unific con la consulta; en el proceso **se agotan todas las posibles soluciones**.Entonces, se dice que 2 trminos unifican si existe algn reemplazo de todas las variables (de los 2 trminos) que haga a los trminos iguales; se dice que una consulta matchea con un consecuente si el predicado es el mismo y hay un reemplazo coherente que hace que todos los argumentos unifiquen. P.ej. con el reemplazo X/homero pasa que X queda igual que homero (primer argumento) y tambin que lisa es igual que lisa (segundo argumento), entonces la consulta padre(X,lisa) unifica con padre(homero,lisa) mediante el reemplazo X/homero.Nos alcanza pensar que un trmino es un individuo (simple o compuesto - estos ltimos pueden tener variables) o una consulta (como en el primer ejemplo).```prolog%Dos individuos iguales unifican ?- 1 = 1.Yes?- homero = homero.Yes?- fecha(1,1,1901) = fecha(1,1,1901).Yes?- [a,b,c] = [a,b,c].Yes%Existen reemplazos de variables que hagan los trminos iguales por lo tanto unifican ?- X = homero.X = homero.?- F = fecha(1,1,1901).F = fecha(1,1,1901).?- fecha(D,1,A) = fecha(1,M,1901).D= 1M= 1A = 1901%Dos individuos distintos no unifican ?- 1 = 2.No?- homero = marge.No?- fecha(1,1,1901) = fecha(1,1,2010).No?- [a,b,c] = [c,b,a].No%No existen reemplazos de variables que hagan los trminos iguales por lo tanto no unifican ?- fecha(D,1,2010) = fecha(1,M,1901). No ?- [1,2,X] = [2,2,3].No?- [1,2,3] = [X,X,3].No```## Y pattern-matching?Bueno, la diferencia entre decir pattern matching y unificacin es bastante gris (algunos autores lo consideran sinnimos). Es muy comn decir "unifica" o "matchea" indistintamente.Vamos a hablar de unificacin de variables en relacin al valor que las mismas toman en base a una consulta y de pattern matching cuando en el encabezado del predicado se determina la forma que tiene que tenerMayormente vamos a hablar de pattern matching al involucrar [individuos compuestos](paradigma-logico---individuos-compuestos.html), ya que a partir de los mismos se pueden definir patrones complejos con los cuales los valores usados en las consultas deberan coincidir.Los patrones ms bsicos que podemos encontrar son los que no limitan en absoluto qu valores pueden matchear (las variables) y los que slo matchean si son exactamente iguales (valores concretos). Por ejemplo, una solucin de factorial podra resolverse usando pattern matching de modo que existen dos definiciones: una que slo es vlida para el factorial de 0 y otra que es vlida para cualquier nmero.```factorial(0,1).factorial(N,F):-N>0,MisN-1,factorial(M,FM),FisN*FM.```Si hacemos las siguientes consultas:```?-factorial(2,Factorial).```El 2 no matchea con el 0, pero s con la variable N, por ende slo la segunda clusula es considerada para responder a la consulta.```?-factorial(0,Factorial).```El 0 matchea con el 0 y tambin con la variable N, por ende ambas clusulas son usadas para responder. Sin embargo, si la variable N se unific con el valor 0, la consulta N &gt; 0 da falso y no contina ejecutando porque ya fall.Al trabajar con individuos compuestos podemos usar otro tipo de patrones que restrinjan parcialmente qu valores pueden pueden matchear." + +} , + +{ + +"title" : "Uso de features de lenguajes dinamicos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/uso-de-features-de-lenguajes-dinamicos.html", +"date" : "", +"content" : "# TerminologaEl trmino "lenguaje dinmico" es usado en la industria con poca rigurosidad. En lugar de intentar de dar una definicin precisa, sealaremos dos caractersticas tpicas de estos lenguajes (aunque bien se podran incluir muchas ms):- Presentan [chequeo de tipos dinmico e implcito](esquemas-de-tipado.html)- Presentan facilidades para [metaprogramar](metaprogramacion.html), no limitndose a la [introspeccin](reflection-introspection.html) sino tambin haciendo uso intensivo de [auto-modificacin](reflection-self-modification.html)Es interesante marcar que la primera caracterstica no es suficiente para hacer dinmico al lenguaje: si pudieramos reemplazar el sistema de verificacin de tipos de Java para que fuera realizado enteramente en tiempo de ejecucin, pero mantuviramos su modelo de objetos y API de metaprogramacin tal como la conocemos, seguira siendo un lenguaje "esttico": el tipado dinmico no es condicin suficiente.Por otro lado, el tipado dinmico no es en teora una condicin necesaria para la metaprogramacin, pero s lo simplifica notablemente: la auto-modificacin en lenguajes con tipado esttico requerira de sistemas de tipos mucho ms complejos que los que estamos acostumbrados a ver en la mayora de los lenguajes.# Features destacadosA continuacin mencionamos algunos features destacados por su utilidad para metaprogramar y hacer [DSLs](dsl.html).- Envo de mensajes "dinmicos": mandar un mensaje a un objeto a partir de su nombre- Interceptores de cdigo: Los lenguajes dinmicos presentan interesantes capacidades de intercepcin de cdigo, ya que ofrecen puntos en los cuales uno puede "colgarse" del mecanismo de resolucin de mtodos (method lookup). El ms simple y usado de ellos es [method missing](method-missing.html) o does not understand: se evaluar este mtodo siempre que se le envie un mensaje a un objeto que este no entienda. En Groovy tambin existe el anlogo para los accessors (propertyMissing).- Clases abiertas (open classes): Que una clase sea abierta significa que puede ser modificada luego de ser definida, para agregar, quitar o modificar cualquier aspecto de la misma (mtodos, atributos, jerarqua de herencia...)- Autoclases (Eigen Class): una clase exclusiva de esa instancia y que no se comparte con las dems permitiendo modificar la estructura y comportamiento de una instancia especfica en vez de todas las de una determinada clase.- Sintaxis flexible: Algunos lenguajes como Ruby permiten jugar con la sintaxis de modo que se pueda incrementar la expresividad del cdigo. Algunos ejemplos de esto podra ser: - omitir parntesis y puntos en el envo de mensajes - redefinicin de operadores - contextualizar bloques de cdigo de modo que se pueda elegir un receptor implcito de los mensajes# Para profundizar y ver algunos ejemplos- [Referencia para Ruby y Groovy](https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnx1dG50YWRwfGd4OjczNjhhOWY1NjZmNDQxZjU)" + +} , + +{ + +"title" : "Value object", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/value-object.html", +"date" : "", +"content" : "# Introduccin*La definicin de Value Object vara bastante de autor en autor. Algunas visiones diferentes sobre este concepto estn plasmadas [aqu](http://c2.com/cgi/wiki?ValueObject).*Entendemos como Value Object a aquellos objetos que tienen una semntica de valor (en contraposicin con semntica de referencia), es decir cuya identidad no es importante. Dos value objects ser intercambiables, esperando iguales resultados, en tanto ambas instancias exhiban el mismo comportamiento desde el punto de vista del observador. Dicho de otra forma, son objetos para los que podra eventualmente tener una copia del mismo, y dara lo mismo enviarle un mensaje al original o su copia.Una consecuencia importante de que los Value Object no tengan identidad importante, es que no tienen estado visiblemente mutable.Los Value Object pueden ser tambin analizados como un patrn de diseo. Se recomienda el capitulo correspondiente en [este libro](http://homepages.mcs.vuw.ac.nz/~tk/fps/fps-sans-escher.pdf)Los Value Objects pueden tener un estado visible inmutable (por ejemplo, para modelar una fecha), aunque tambin puede darse el caso en que tal estado no exista (por ejemplo, para modelar la funcin identidad) o se encuentre comletamente encapsulado (por ejemplo, una funcin aplicada parcialmente encapsula complementanete el estado de las variables que que fueron encerradas en su contexto)Los Value Objet an puede tener un estado mutable interno, en tanto este no sea expuesto a travs de su interfaz, lo que habilita a que presenten evaluacin diferida en en sus variables de instancia.## Impacto en el diseo## Implementacin## Consideraciones sobre el subtipado y las relaciones de equivalencia### En Java```javapublicclassFinal{privatefinalStringfolio;privatefinalIntegerlibro;privatefinalIntegernota;privatefinalAlumnoalumno;publicFinal(Stringfolio,Stringlibro,Integernota,Alumnoalumno){this.libro=libro;this.folio=folio;this.nota=nota;this.alumno=alumno;}publicbooleanestaAprobado(){returnnota>=4;}publicAlumnogetAlumno(){returnalumno;}//demasgetters}```Ntese que el estado, de existir, de un ValueObject no tiene porqu estar conformado exclusivamente por tipos primitivos (primitive obsession).Tampoco tiene porqu estar desprovisto de comportamiento (dto/anemic object), de hecho, normalmente lo tiene y es funcin de su estado.Un ValueObject puede exponer su estado interno, como tambin puede encapsularlo completamente (ej &#92;[Function Object&#92;])### Scala```scalaclassFinal(valfolio:String,vallibro:Int,valnota:Int,valalumno:Alumno){defestaAprobado=nota>=4}caseclassFinal(valfolio:String,vallibro:Int,valnota:Int,valalumno:Alumno){defestaAprobado=nota>=4}```## En lenguajes con tipado dinmico### en C (como un TAD)Si bien en C no tenemos objetos, podemos tambin implementar TADs con semntica de valor." + +} , + +{ + +"title" : "Variables locales en metodos", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/variables-locales-en-metodos.html", +"date" : "", +"content" : "Se pueden usar variables locales a los mtodos, lo cual puede ayudar la legibilidad o para evitar repetir la evaluacin de una misma consulta a lo largo del mtodo. Son anlogas a las variables locales de procedimientos que deberan conocer de Algoritmos.Cmo se definen y usan: ah va un ejemplo rpido (no importa mucho lo que hace)```smalltalkmiMetodoLoco:unNumero**| varLocal1 varLocal2 varLocal3 |**varLocal1:=4.varLocal2:=varLocal1+5.varLocal3:=varLocal1/unNumero.^(varLocal1max:varLocal2)min:varLocal3.```En este mtodo se definen tres variables locales entre pipes (|). Las primeras tres lneas luego de esta declaracin asignan las tres variables (o sea, hacen que referencien a un objeto). Luego puedo mandarle mensajes a los objetos referenciados por esas variables y usar esas referencias tantas veces como quiera." + +} , + +{ + +"title" : "Variables y metodos de clase", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/variables-y-metodos-de-clase.html", +"date" : "", +"content" : "# Mensajes y Mtodos de claseLas clases son objetos, y como todos los objetos pueden tener atributos y ademas les podemos mandar mensajes. Pero las clases son objetos con responsabilidades especiales, la ms comn es la de crear nuevos objetos. Cada vez que a le mando el mensaje **new** a una clase obtengo una nueva instancia de esa clase. Podemos crear nuevas instancias en cualquier momento de nuestro programa (en el workspace, dentro de un mtodo, etc).Entonces, los mensajes de clase son mensajes que entienden las clases, no las instancias de las mismas. El nombre (selector) de un mensaje de clase se escribe igual que siempre (empieza con minscula).Algunos ejemplos:Workspace:```smalltalkpepita:=Golondrinanew.```new es uno de los primeros mensajes de clase que aprendemos: nos devuelve una nueva instancia de la clase que recibe el mensaje. En este caso, devuelve una golondrina.Workspace:```smalltalkhoy:=Datetoday.```today es un mensaje de clase que le mando a la clase Date y me devuelve un objeto que representa la fecha de hoy.Workspace:```smalltalkitems:=Bagwith:'brujula'with:'botellaDeGrogXD'with:'catalejo'.```with:with:with: es un mensaje que entienden las clases de colecciones (en este caso Bag es la clase que recibe el mensaje). with:with:with: devuelve una nueva coleccin, que tiene los tres elementos adentro. En ste caso, devuelve un bag con la brjula, la botella y el catalejo.En general es deseable tener una forma de crear objetos que ya estn inicializados adecuadamente para poder usarlos inmediatamente, y no que arranquen en un estado invlido y requieran ser configurados a posteriori.## Cmo escribo mtodos de clase?Cada mensaje de clase debe tener asociado un mtodo de clase (su codificacin).- En Pharo: En el segundo panel del System Browser, apretando el boton **class**, escriben el mtodo como hasta ahora. (No se olviden de volver a apretar **instance** para escribir metodos de instancia)- En el parcial: simplemente pongan **(MC)** al lado del mtodo, para diferenciarlo de los mtodos de instancia.Workspace:barbanegra:=PiratanuevoConItems:itemsebriedad:100monedas:1500.El mensaje nuevoConItems:ebriedad:monedas: se lo mando a la clase Pirata y me devuelve un nuevo pirata ya inicializado con los items, la ebriedad y las monedas que le indiquemos.Codificacin:```smalltalk#Pirata(MC)>>nuevoConItems:losItemsebriedad:nivelEbriedadmonedas:unasMonedas|unPirata|unPirata:=selfnew.unPirataitems:losItems.unPirataebriedad:nivelEbriedad.unPiratamonedas:unasMonedas.^unPirata.```Recordemos que, como el que recibe este mensaje es una clase, ac **self es la clase**, no una instancia. El motivo por el cual es importante usar self en vez de escribir el nombre de la clase (en este caso Pirata) es porque estos mtodos tambin se heredan, y si subclaseamos Pirata no se va a comportar como queremos cuando le mandemos nuevoConItems:ebriedad:monedas: a la subclase. Al usar self indicamos que el mensaje debe enviarse al objeto que recibi nuevoConItems:ebriedad:monedas:, o sea que si se lo mandamos a una subclase de Pirata, la instancia creada ser de dicha clase.# Que son las variables de clase? Para que sirven?Las variables de clase nos sirven cuando queremos que nuestros objetos tengan alguna referencia a algn valor, que sea el mismo para todas las instancias de esa clase, y que ademas pueda cambiar (por eso usamos una variable y no hardcodeamos ese valor en el cdigo del programa, asumiendo que es posible).Si usramos una variable de instancia con la intencin de settear el mismo valor a todas las instancias de esa clase, y luego queremos cambiar el valor de modo de afectar a todas las instancias, tengo que poder encontrar todas las instancias ya existentes para poder mandarles el mensaje para que actualicen su referencia... Y si tengo muchos muchos objetos eso no esta bueno, no slo por la complejidad innecesaria del problema, sino tambin porque la performance puede verse afectada. Este problema desaparece si tengo un nico objeto que conozca este valor que quiero que varios objetos conozcan, y como todo objeto conoce la clase a la que pertenece, podemos dejar que sea responsabilidad de la clase recordar y manipular este estado, y que sus instancias usen ese valor cuando lo necesiten.Si tengo una variable de clase y cambio el valor al que referencia, automticamente todas las instancias que yo cree a partir de esa clase en la vida van a conocer ese nuevo valor, porque lo conoce su clase y ellas conocen a su clase :)# Diferencia con las variables de instanciaLas variables de instancia son propias de cada objeto, si cambio una referencia en un objeto la referencia de otro de la misma clase no cambia (aunque las variables se llamen igual). Si cambio la referencia de una variable de clase, todas las instancias van a verse afectadas, ya que no es una referencia propia.En Smalltalk, para declarar una variable de instancia (por ejemplo, dada una clase Pirata, para decir que cada pirata conoce cuntas monedas tiene) debamos indicarlo de esta forma:```smalltalkObjectsubclass:#PiratainstanceVariableNames:'monedas'classVariableNames:''category:'Yaaaar'```Para declarar una variable de clase en cambio, el nombre de la variable debe ir entre las comillas que siguen a classVariableNames:, por convencin inician con mayscula. Suponiendo que el dinero mximo que tiene que tener un pirata para poder saquear un objetivo es igual para todas las misiones de saqueo es el mismo, podemos ponerlo en una variable de clase```smalltalkObjectsubclass:#SaqueoinstanceVariableNames:''classVariableNames:'DineroMaximo'category:'Yaaaar'```# Como las usamos?Dentro de un mtodo de instancia de Saqueo podemos directamente usar una variable de clase definida para la clase Saqueo, por ejemplo:```smalltalk#Saqueo>>esUtil:unPirata^(unPiratadineroDisponible>esUtil:unPirata^(unPiratadineroDisponible> dineroMaximo****^DineroMaximo**```Por ltimo, una forma ms correcta sera poniendo **self class**, de esta manera:```smalltalk#Saqueo>>esUtil:unPirata^(unPiratadineroDisponible>dineroMaximo^DineroMaximo```La razn por la que es ms correcta, tiene que ver con la existencia de [Herencia](herencia.html) como se mencion anteriormente. As damos la posibilidad a una subclase a redefinir dineroMaximo." + +} , + +{ + +"title" : "Variables", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/variables.html", +"date" : "", +"content" : "# ReferenciasEn objetos una variable es una **referencia** a un objeto. La mayora de las referencias pueden ser reapuntadas a otros objetos mediante la operacin de [asignacin](transparencia-referencial--efecto-de-lado-y-asignacion-destructiva.html). Al hacerlo eso no modifica al objeto previamente referenciado.Hay distintos tipos de referencias, dependiendo del contexto en el cual son declaradas:- atributos: se usan para que el objeto mantenga un estado propio.- locales: se declaran dentro de un mtodo, slo son visibles desde el mismo, y no sobreviven a su ejecucin.- parmetros: forman parte de la firma del mtodo, no pueden ser reapuntadas a otros objetos dentro del mtodo.## Asignacin de variablesLa asignacin de variables se logra de la siguiente forma:```scalavariable=expresion-que-devuelve-un-objeto```y debe interpretarse que cuando se evala esta lnea, la variable referencia al objeto resultado de la expresin de la derecha.Entonces, al asignar una variable **no estoy creando ningn objeto** ni estoy cambiando al objeto referenciado anteriormente por dicha variable, slo se cambia cul es el objeto al que est apuntando esa referencia.### var y constEn Wollok, las referencias pueden declararse como variables (con la palabra reservada `var`) o como constantes (con la palabra reservada `const`). Las constantes estn pensadas para ser usadas siempre que no se espere que la referencia pueda cambiar de valor, con lo cual intentar asignar una constante luego de su inicializacin no est permitido.```scalavar edad = 15const iva = 21edad = 16 // esto anda perfectoiva = 19 // esto tira error en tiempo de compilacin```Error comn: qu significa "cambiar un objeto"? - Lo cambio **por otro**?- O le cambio **sus atributos**?Miremos el siguiente ejemplo:```scalaconst laPreferida = pepita // atentos al constlaPreferida.volar() // Qu sucede en este caso? Da error? laPreferida = pepona // Y en este caso?````laPreferida.volar()` no da error. Esto es porque al enviar el mensaje `volar()`, `laPreferida` (que apunta al mismo objeto que `pepita`) est cambiando su **estado interno**, su energa. Pero la **flecha** `laPreferida` no se modifica! Se modifica slo la energa de pepita al volar.En cambio, en `laPreferida = pepona` s hay un error de compilacin. Estoy intentando modificar a dnde apunta `laPreferida`, pero como esa referencia es `const` nunca podr dejar de apuntar a pepita.Es importante entender que `const laPreferida` **no significa que el objeto no pueda modificar su estado interno, sino que no puedo hacer que la flecha laPreferida apunte a otro objeto**.## InicializacinUn problema comn que suele darse con atributos de los objetos es olvidarse de inicializarlos.Lo que sucede cuando una variable no ha sido inicializada puede variar de un lenguaje a otro: algunos (por ejemplo Smalltalk) tienen un objeto especial para representar la nada que entienden muy poquitos mensajes, otros (como Java o Wollok) directamente usan un valor primitivo. Pero lo importante es que para poder usar una variable de forma razonable, la misma debera referenciar a un objeto que entienda los mensajes que esperamos mandarle, de lo contrario se generar un error.Cul es el momento adecuado para inicializar un atributo? Si bien podran darse situaciones en las cuales se quiera o necesite postergar la inicializacin de un atributo, lo ms comn es querer inicializar los atributos al momento de la creacin del objeto, de esa forma nunca se llegar a un estado en el cual el se le mande un mensaje al objeto y el mismo falle porque no se haya inicializado un atributo previamente.En Wollok podemos inicializar las variables al momento de declararlas. Eso en general es suficiente para trabajar con objetos bien conocidos (como en el ejemplo que se muestra ms adelante). En caso de trabajar con objetos instanciados a partir de [clases](clases.html), es posible inicializar los atributos con valores distintos para cada instancia usando las [herramientas de instanciacin](herramientas-de-instanciacion.html) disponibles (en otros lenguajes en los cuales las clases son objetos, como Smalltalk, esto se logra mediante mensajes a las clases).## Ejemplo completoDado el siguiente cdigo Wollok:```scalaobjectpepita{varenergia = 100methodenergia(cantidad) {energia=cantidad}}```... yluegolemando el mensaje...```scalapepita.energia(50)```Cuando el objeto se crea, la variable energa se inicializa apuntando al objeto 100. Al mandar el mensaje para settearle la energa, el atributo energia que tiene pepita pasa de apuntar a 100 a apuntar a 50. O sea que slo cambia a quin conoce pepita mediante la referencia energia.SIEMPRE lo que se encuentre a la izquierda de la asignacin debe ser una variable, no se puede asignar un objeto (y por el mismo motivo no se puede asignar un envo de mensajes). Las siguientes expresiones son invlidas:```scala3=5 // <---3esunobjeto,nounareferencia!!!pepita.energia()=10 // <---pepita.energia()esunenvodemensajes,nounareferencia!!!```En ningn caso vamos a poder modificar desde fuera del objeto que tiene una referencia el valor de la misma, siempre hay que mandarle un mensaje a ese objeto para que la cambie. Esto est relacionado con la idea de [encapsulamiento](encapsulamiento.html), que es una de las bases del paradigma de objetos.# Atributos: errores comunesLos atributos son obviamente muy tiles, ya que permiten que un objeto recuerde toda la informacin que necesita para poder usarla en cualquier momento. Sin embargo, hay que ser criteriosos respecto a cundo usarlos, ya que pueden ser el motivo de inconsistencias y dificultad para mantener nuestros programas.Los siguientes son los algunos errores comunes de ver respecto al uso de atributos:- Atributos redundantes: si cierta pieza de informacin puede ser calculada a partir de otra, no uses un atributo que tenga que ser mantenido consistente, us un mtodo que calcule lo que necesits a partir de la otra informacin disponible. Para ms informacin pods leer [este artculo](oo-temporary-variable.html)- Atributos innecesarios: no hay que perder de vista que nuestro programa es un **modelo**, y por ende no hace falta que el objeto recuerde informacin que luego no va a ser usada.- Uso de atributos en vez de locales: si necesitamos recordar cierta informacin slo dentro de la ejecucin de un mtodo, lo correcto es usar una local, no un atributo.Como regla general para evitar estos problemas, preguntate: hay alguna forma de no usar un atributo para lo que ests haciendo? si la hay, ***no uses un atributo***.Y las referencias circulares? Es perfectamente vlido que dos objetos se conozcan entre ellos, en el caso de que sea necesario obviamente, las reglas anteriores valen tambin para esto. El nico recaudo que hay que tener es asegurar la consistencia del estado de ambos objetos, lo cual puede simplificarse asegurando que esas referencias se modifiquen dentro de una misma operacin, y no de forma independiente." + +} , + +{ + +"title" : "Warning singleton variables", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/warning--singleton-variables.html", +"date" : "", +"content" : "Las singleton variables son variables que vos escribiste en tu predicado pero no se usan. Por ejemplo:"Soy feliz si tengo algun amigo"```prologesFeliz(Alguien):-amigoDe(Alguien,**UnAmigo**).```Ah la variable UnAmigo no la uss en otro lado, por lo que te dice que es Singleton. Como a vos no te interesa "usar" a ese UnAmigo (Slo te interesa saber si existe, no quin es), pods poner una variable annima:```prologesFeliz(Alguien):-amigoDe(Alguien,**_**).```Y as ya no te chilla.Ojo, a veces pasa que escribs mal una variable, entonces te dice "eh, singleton, sta no la ests usando en otro lado" Por ejemplo:```prologesFeliz(**Alguin**):-amigoDe(**Alguien**,_).```Y ah slo tens que arreglar tu error de tipeo.En resumen, si tens un Warning,- puede ser que tu programa igual ande perfecto (en el primer caso la variable annima funciona igual que una comn), bien- puede ser que por un error de tipeo tu programa no ande (qu bueno que nos avise).- En general, los warnings nos deberan hacer pensar si escribimos bien las variables, y si lo hicimos bien, deberamos entonces revisar la lgica del predicado (pifiarla en eso es un error ms grave)" + +} , + +{ + +"title" : "Xtend - control de versiones", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/xtend-amigandonos-git.html", +"date" : "", +"content" : "No todos los archivos deben subirse al repo. Como regla general no deberan subir archivos que se puedan generar a partir de otros, por ejemplo:- los archivos `.java` que se generan a partir del cdigo Xtend (en `target/xtend-gen/main`)- los binarios que se generan a partir del cdigo fuente de ustedes (en `target/classes`). Ocupan espacio en el repositorio y se corre el riesgo de estar trabajando con versiones desactualizadas.- archivos de configuracin propios de Eclipse, como `.project`, `.classpath` y el directorio `.settings`. Todos estos se generan a partir del `pom.xml` cuando hacemos Maven > Update, y por este motivo no es bueno trabajar con los archivos de Eclipse ni tenerlos en cuenta en el control de versiones.# Cmo no subir esos archivosDebemos crear un archivo `.gitignore` (que en Wollok se los cre el propio entorno), en la carpeta raz del proyecto, que debe tener al menos esta lista:```bash/target/.classpath.projectbingenerated*.settings```Fjense que hemos eliminado todos los archivos que se pueden generar en base a definiciones originales. Esto da como resultado un repositorio con menos cantidad de archivos y mayor calidad de los mismos. Por lo general, deberamos evitar subir archivos binarios (salvo imgenes o archivos encriptados con informacin sensible), dado que ocupan ms espacio y no se puede comparar diferencias entre versiones, solo saber si cambi.# Recomendaciones para trabajar con mi grupo- Cuando empiezo el da primero sincronizo el repositorio para ver los cambios que no tengo en el cdigo. Si no hay cambios, simplemente corro los tests y empiezo a codear como un campen. Si no... - Acepto los cambios entrantes y en caso de ser necesario resuelvo conflictos - Corro los tests y veo que todo anda sobre ruedas - Vuelvo a sincronizar y veo que ya no quedan ni conflictos ni cambios sin aceptar - Subo mis cambios al repositorio remoto para que mis compaeros lo vean- Ahora s, a programo, programo, programo... y cuando termino, corro los tests- Y vuelvo a sincronizar contra el repositorio remotoEn resumen:- No pasa un da de trabajo sin hacer un commit y push al repositorio remoto. Esto implica planificar mi trabajo para que pueda subir algo al repositorio sin que rompa todo: **hay que partir un cambio grande en pequeos pasos** (iterativo, incremental).- Nunca deberan subir nuevos fuentes al repositorio sin explicar brevemente qu cambiaron. Si los mensajes son descriptivos (y "fix", "asdsadsa" o "arreglo una cosita" definitivamente no lo son) rpidamente puedo detectar qu modificaron mis compaeros con slo leer lo que escribieron en los commits. Una buena descripcin me ayuda tambin a entender qu es lo que se modific y por qu razn, especialmente til a la hora de solucionar un conflicto o entender por qu se rompieron los tests.- El que rompe los tests paga las facturas.# Metodologa para trabajar en grupo- los tests tienen que estar en verde **siempre**- los tests son de todos y todos somos responsables por mantenerlos- si encontramos un bug y no haba un test que lo probaba agregamos uno- los tests son rpidos de correr (no pueden tardar 10 minutos)# Git por consola o Git con una herramienta visual?Da lo mismo, eleg la herramienta que mejor te resulte. eGit no es la gran cosa y hay otras opciones (tens los links en la pgina), lo importante es cmo te organizs con tus compaeros.___- [Siguiente paso: Gua rpida de Xtend](xtend-guia-rapida.html)- [Volver al men principal del entorno Xtend](xtend-principal.html)" + +} , + +{ + +"title" : "Cómo generar un proyecto Xtend nuevo", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/xtend-creacion-proyecto.html", +"date" : "", +"content" : "Para realizar las prcticas, vas a crear un proyecto desde cero. Como ahora hay muchas ms opciones, te dejamos una gua simple de cmo iniciarte.# Crear proyecto MavenTodos los ejemplos que vas a descargar de la materia, as como los proyectos en los que vas a trabajar, se basan en la tecnologa Maven. Para crear un proyecto Maven, te dejamos esta animacin:![image](/img/languages/creatingNewProject.gif)- Seleccionamos New > Project... Maven Project- Chequeamos "Skip archetype selection" ya que no lo usaremos, y luego Next- En la siguiente pantalla, escribimos cualquier cosa en "groupId", que es un valor que luego borraremos, pero que si lo dejamos vaco Eclipse nos mostrar un error. Y el nombre de nuestro proyecto o `artifactId`, ste s es importante, seguimos la nomenclatura de paquetes de Java, para que no haya confusiones en los nombres: `ar.edu.unsam.prueba` identifica nuestro proyecto en todo el mundo- cuando finalizamos, se genera un proyecto con un archivo pom.xml, que es fundamental para que Eclipse regenere el proyecto en otra mquina y descargue las dependencias# Configuracin de un proyecto MavenEl acrnimo POM es por "Project Object Model". El archivo `pom.xml` es el core de la configuracin de un proyecto maven. Es un solo archivo de configuracin que contiene la mayora de la informacin requerida para el build de un proyecto.## Pom, pom, pom, pom...Para comenzar a escribir la configuracin del proyecto en un archivo `pom.xml` existen algunas opciones:- Inicializar un proyecto maven desde 0 desde la terminal con el comando `mvn archetype:generate`. Al hacer esto maven nos pedir los datos iniciales para inicializar el proyecto (artifactId, groupId, etc) y nos dejar un `pom.xml` creado y listo para usar/modificar.- Crear un proyecto maven desde eclipse u algn otro IDE.- Copiarse un `pom.xml` de un proyecto maven existente y adecuar los valores de los campos que identifican el proyecto.Te dejamos entonces el modelo de proyecto Maven por defecto para la cursada de Algoritmos 2 (UNSAM) del ao 2021: [pom.xml de ejemplo](pom-algo2.xml). Luego tendrs que- renombrar el archivo a `pom.xml`- copiarlo dentro del directorio raz de tu proyecto ya creado- actualizar en base a los nombres de tu proyecto (el _artifactId_ y _groupId_)- revisar las dependenciasPara profundizar un poco ms sobre lo que contiene un archivo de Maven, te recomendamos [este artculo](maven.html).# Sincronizacin entre Eclipse y MavenCada vez que hagamos un cambio en el archivo `pom.xml`, nos aparecer un mensaje de error en la solapa **Problems**, que se soluciona forzando la sincronizacin entre Eclipse y Maven (dado que cada uno maneja su propia estructura de proyectos Java). Como regla general, **siempre que necesitemos agregar alguna biblioteca, o dependencia, debemos hacerlo en el archivo pom y no desde las opciones que ofrece el Eclipse, porque nuestros compaeros o los docentes no tendrn esa biblioteca**. Para sincronizar Maven y Eclipse, nos paramos en el proyecto y con un botn derecho elegimos "Maven > Update Project".# Primeros pasos![image](/img/languages/firstClass.gif)Ahora solo nos queda eliminar la lnea groupId (con Ctrl + D), formatear el pom.xml (con Ctrl + Shift + F) y crear nuestra primera clase Perro. Es importante notar que tendremos dos carpetas donde ubicaremos los fuentes:- `src/main/java`: donde irn las clases- `src/test/java`: donde irn los testsPor eso, nos ubicamos en `src/main/java` y con un botn derecho, New > Xtend Class (es importante que hayas configurado el Eclipse para que no est escondida esta opcin).## Generacin de archivos .javaEn `src/main/generated-sources` vas a tener los archivos `.java` que se generan en base a los archivos de xtend. No los toques! Porque cada cambio que hagas en tu clase xtend va a pisar los cambios de los archivos `.java`. En general no deberas mirar nunca el java que genera, porque adems utiliza construcciones menos simples que si programaras directamente en java.# RecomendacionesA continuacin te dejamos algunas recomendaciones para que tu estada en Eclipse + Xtend sea ms feliz:- Formatear el cdigo! Nunca nos olvidemos de que nuestro cdigo tiene que ser entendible para el resto de la humanidad. Adems, el Eclipse lo hace solo (Ctrl + Shift + F).![image](/img/languages/formattingCode.gif)- Utilizacin de packages (paquetes). Es una buena prctica agrupar las clases afines en paquetes para organizar semnticamente el cdigo. No hay una gua firme a seguir con respecto a cmo organizar nuestro cdigo, ya que suele depender del contexto en el cual estamos trabajando, pero a medida que veas nuestros ejemplos y vayas haciendo las prcticas notars que hay clases que se pueden agrupar en contextos similares. Te dejamos un ejemplo```bashproyectohomeregistrationProfile.xtendUser.xtendsettingsCustomPrivacy.xtendDefaultPrivacy.xtendPrivacy.xtendSetting.xtend```De esta manera, logramos mayor granularidad en la organizacin de nuestras clases.___* [Siguiente paso: Sobre el control de versiones](xtend-amigandonos-git.html)* [Volver al men principal del entorno Xtend](xtend-principal.html)" + +} , + +{ + +"title" : "Guia rapida de Xtend", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/xtend-guia-rapida.html", +"date" : "", +"content" : "La siguiente es una gua de _syntactic sugars_ de Xtend, algunos de los cuales trabajan conceptos ms profundos que veremos a lo largo de la materia.# Definicin de una claseNo tenemos objetos en Xtend, slo clases. Aqu dejamos un ejemplo```scalaclass Ave { static int ENERGIA_MINIMA = 10 @Accessors int energia = 0 def volar() { energia = energia - 10 } def comer(int cuanto) { energia = energia + (cuanto * 2) } def esFeliz() { energia > ENERGIA_MINIMA } def resetearEnergia() { energia = 0 }}```* podemos escribir mltiples clases en un archivo Xtend* la definicin de la clase se encierra entre llaves* la variable ENERGIA_MINIMA es esttica, esto significa que **todas las instancias comparten la misma variable** (lo que tambin se llama variable de clase), suele usarse como constantes o valores que difcilmente cambien.* la variable energia **es una variable de instancia** porque cada objeto Ave tiene su propio valor.* las variables de instancia y de clase deben anotarse con el tipo, en este caso ambos son int* la variable `energia` tiene la anotacin `@Accessors`, que permite definir getters y setters automticos* los mtodos volar, comer y esFeliz necesitan la palabra `def` para indicar que son mtodos. Algunos producen efecto (volar y comer) y otros simplemente devuelven un valor (esFeliz)* no es necesaria la palabra `return` al final de cada mtodo, pero en algunos casos veremos que es necesaria* no siempre es necesario hacer anotaciones de tipo sobre los mtodos, como veremos ms adelante# Referencias variables y valoresEn Xtend, al igual que muchos otros lenguajes, se diferencian las referencias como* **Variables**: son referencias que pueden inicializarse apuntando a un objeto, y luego reasignarse a otro. Justamente "varan":```scalavar String unString = "Pepito"unString = "Otro String"```* **Constantes**: son referencias que nacen apuntando a un valor y no pueden ser modificadas para apuntar a otro objeto. Seran como "constantes".```scalaval String constante = "Constante"constante = "Otro" // **Tip**: para que te aparezcan los smbolos `` que son difciles de encontrar en el teclado, simplemente utiliz las teclas `Ctrl` + `Espacio` dentro de la definicin del string y aparecern solas## NmerosExisten muchos tipos de datos diferentes para nmeros:* **int**: es un nmero entero que admite negativos pero sin decimales* **double**, **float**: son nmeros reales que admiten decimales pero con errores en las operaciones, es por ello que no debemos usarlo para operaciones sensibles (como transacciones bancarias o que requieran clculos exactos)* **BigDecimal**: es el tipo de dato que conviene utilizar ya que no produce errores de redondeo (permite trabajar con una cantidad exacta de decimales y truncarlos o redondearlos en caso de ser necesario)* Tambin existen las variantes "objetosas" de int, double y float que son Integer, Double y Float. La principal ventaja es que son objetos, y podemos enviarle mensajes (concretamente ms mensajes) que a las versiones en minscula, que son _tipos primitivos_. Es posible "envolver" en una variable Integer cualquier int, la conversin se da automticamente por el compilador de Java y se llama "autoboxing":```scalavar i = 0 // intvar pi = 3.14d // doublevar saldo = new BigDecimal(1500) // BigDecimalvar Integer otroI = i // otroI es un enterootroI.bitwiseNot // puedo enviar un mensajes```## ColeccionesExisten literales para definir listas, conjuntos y mapas (dictionaries):```scala// Lista inmutable:val myList = #['Hello', 'World']// Set inmutableval mySet = #{'Hello', 'World'}// Mapa/Diccionario inmutableval myMap = #{'a' -> 1 , 'b' ->2}```Recordemos que* **listas**: respetan el orden en el que se agregan (como una fila) y admiten duplicados.* **conjuntos**: no tienen orden y tampoco admiten duplicados. Dos objetos son iguales en base a la definicin de equals() y hashCode().* **mapas**: tambin llamados dictionaries, son un conjunto de pares clave/valor. Se acceden por clave.## RangeEs posible generar un rango de nmeros, por ejemplo para iterar una cantidad de veces:```scala#[1 .. 10].forEach [ ... ] // [1..10] genera la lista de 1 a 10#[1 .... 10].forEach [ ... ] // [1>..10] genera la lista de 2 a 10````.. facturas = newArrayListSet domicilios = newHashSetList nombres = newArrayList("nahuel", "rodrigo", "marina")```Pods utilizar `newLinkedList`, `emptyList`, `emptySet`, `emptyMap`, `newInmutableMap`, `newImmutableSet`, `newImmutableList`, `newLinkedHashSet`, `newTreeSet`, `newHashMap`, `newLinkedHashMap`, `newTreeMap`. La ventaja que tienen es que permiten pasarle parmetros variables (tantos como elementos necesites) y trae implementaciones por defecto para algunas colecciones que necesitan comparators (tens que estudiar ms a fondo [**Colecciones en Xtend**](https://docs.google.com/document/d/1lzOStySb8i94oVvZUIxkgymf2tuCDuXzqSTnClPqKSM/edit?usp=sharing))## Inferencia de tiposXtend cuenta con inferencia de tipos, lo que permite* que existan chequeo de tipos* pero que la mayora de las veces no sea necesario definir los tipos de las expresionesVemos un ejemplo en vivo, mostrando cmo cambia la solapa "Outline" cuando modificamos el cdigo:![image](/img/languages/xtendTypeInference.gif)Aqu vemos que incluso Xtend detecta expresiones que no tienen sentido, como cuando hicimos:```scaladef esFeliz() { energia > ENERGIA_MINIMA "si"}```El hecho de generar una expresin `energia > ENERGIA_MINIMA` no causa efecto en el objeto y tampoco se devuelve (porque se pisa por la expresin "si" que es devuelta como retorno del mtodo).Volviendo a la inferencia de tipos, es fundamental poder contar con un lenguaje que tenga chequeo de tipos para detectar errores en forma temprana pero **que no me obligue a definir los tipos todo el tiempo**. La definicin de tipos es obligatoria para las variables de instancia y de clase de los objetos, y en algunos casos cuando la definicin de mtodos polimrficos puede resultar ambigua para Xtend. En cualquiera de esos casos vas a ver un mensaje de error o de advertencia para que definas el tipo que mejor se ajuste.## CasteosSi bien toda expresin tiene un tipo y Xtend suele inferirlo bastante bien, a veces es necesario hacer _downcasting_ o forzar que una expresin pase por un tipo de datos:```scala(42 as Integer)(cliente as Cliente)```En general la expresin es, entre parntesis: (`valor/variable` as `tipo`)# Definicin de propiedadesLa anotacin @Accessors puede hacerse sobre una variable, como hemos visto antes:```scalaclass Ave { @Accessors int energia = 0```En este caso se crean getters y setters para energia, **transformndolo en una propiedad**.```scalaclass Ave { @Accessors(PUBLIC_GETTER) int energia = 0```En este caso se crea un getter pblico para la variable energia. Otras variantes son: crear slo un setter pblico o crear getters o setters con diferentes visibilidad.Por ltimo, podemos anotar la clase con @Accessors```scala@Accessorsclass Ave { int energia = 0 int vecesQueVolo = 0```en este caso, se crean getters y setters para todas las variables de dicha clase.# Shortcut para acceder a propiedadesCuando usamos un objeto que tiene propiedades (par getter y setter), podemos cambiar un poco la sintaxis para que se vea ms simple. En el ejemplo anterior del Ave:```scalaval pepita = new Ave()pepita.energia = 100 // ENERGIA_MINIMA }}class Golondrina extends Ave { override esFeliz() { true }}class Torcaza extends Ave { int vecesQueVolo = 0 override volar() { super.volar() vecesQueVolo++ }}```Aqu vemos que* Golondrina y Torcaza heredan de Ave, indicado mediante la palabra clave `extends`* Golondrina **redefine** el comportamiento de esFeliz, lo pisa, y esto requiere la palabra clave `override` (no funciona si intentamos definirlo con `def`)* Torcaza tambin lo redefine, pero fuerza a llamar al comportamiento de la superclase mediante la palabra clave `super`, indicando luego el mensaje a aplicar. Como regla general solo deben utilizar `super` cuando no puedan utilizar `self`, como en este caso (entraran en loop infinito)# Clases y mtodos abstractosPodemos definir a Ave como clase abstracta, esto producir que no podamos instanciar objetos Ave. Una clase abstracta puede definir solo la interfaz de un mtodo, lo que se conoce como mtodo abstracto. Veamos el siguiente ejemplo:![image](/img/languages/xtendAbstractClassesAndMethods.gif)En el ejemplo:* primero definimos Ave como abstracta* eso provoca que el compilador Xtend tire un error cuando queremos instanciar un Ave en la clase Ornitologo* lo corregimos instanciando una Golondrina* luego, queremos definir un mtodo abstracto: esFeliz. Para ello reemplazamos la definicin por una cscara que solo dice que esFeliz debe devolver un booleano. Dado que no hay cdigo Xtend nos fuerza a definir el tipo de retorno del mtodo (y de sus parmetros) porque no puede inferirlo.* todos los mtodos abstractos deben estar implementados en las subclases: el compilador nos avisa que falta la definicin de esFeliz() en Torcaza. Con un botn derecho "Add unimplemented methods" pegamos la definicin copiada.* como nos falta la constante que estaba en Ave, la bajamos mediante `Alt` + `Flecha abajo`y finalmente todo compila.# ConstructoresUn constructor se define con la palabra reservada `new` (equivalente al `constructor` de Wollok):```scala@Accessorsclass Golondrina { int energia new() { this(100) // llama al constructor con parmetros // para llamar al constructor de la superclase es necesario utilizar super(params) } new(int energia) { this.energia = energia }}```* Por defecto, si no hay constructores se genera uno por defecto sin parmetros y no hace falta definirlo* Es posible definir mltiples constructores, como vemos en el ejemplo, con diferente cantidad de parmetros o de tipos* Cuando definimos constructores sobre una clase, se pierde el constructor por defecto* **Los constructores de Xtend no se heredan**# BloquesUn bloque permite definir una porcin de cdigo, tambin llamada expresin lambda:```scalaval cuadrado = [ int num | num ** 2 ]cuadrado.apply(5)```De esta manera podemos enviar bloques como parmetros, algo muy til para trabajar entre otras cosas con las colecciones (`map`, `filter`, `fold`, etc.)La sintaxis general es```scala[ | ... ] // bloque sin parmetros[ elem | ... ] // bloque con un parmetro[ int a, int b | a + b ] // bloque con dos parmetros```## Variable implcita itDe la misma manera que cuando estamos dentro de una clase, podemos acceder a una variable de instancia con `this````scalathis.energia```o sin l:```scalaenergia```tambin podemos usar una variable implcita `it` dentro de un mtodo.```scalaval it = new Ave()volar // equivale a it.volar()comer(2) // equivale a it.comer(2)```Dentro de una expresin lambda, `it` es la variable implcita del primer parmetro, por lo tanto todas estas expresiones son equivalentes:```scalaalumnos.filter [ alumno | alumno.estudioso() ]alumnos.filter [ it | it.estudioso() ]alumnos.filter [ it.estudioso() ]alumnos.filter [ it.estudioso ]alumnos.filter [ estudioso ]```![image](/img/languages/xtendItImplicitVariable.png)# Manejo de nullsLos valores nulos son siempre un dolor de cabeza, Xtend tiene algunos trucos para facilitar un poco ms el trabajo con ellos.## Elvis operatorParece un emoticn, pero `?:` es un shortcut para utilizar un valor por defecto cuando una expresin pueda ser nula:```scalaval nombre = person.firstName ?: 'You'```Si la expresin que est a la izquierda se evala como null, `nombre` se asigna a la segunda expresin.## Null safe operatorTambin podemos resolver envos de mensajes a referencias que potencialmente podran ser nulas:```scalaval mejorAlumno = alumnos.find [ ... ]...mejorAlumno?.felicitar()```En este caso, el operador `?.` es equivalente a preguntar `if (mejorAlumno) mejorAlumno.felicitar()`## Comparar referenciasDespus de varios cambios, Xtend dej las cosas como la mayora de los lenguajes. Tenemos dos formas de comparar referencias:```scalaref1 == ref2 // compara por igualdad, esto significa que son iguales si son las referencias // apuntan al mismo objeto o bien, en base a la definicin del mtodo equals // en la clase ref1 (sabiendo que ref1 no es nulo) // en la clase asociada a ref1ref1 === ref2 // compara por identidad, esto significa que son iguales si las referencias // apuntan al mismo objeto en memoria, determinado por la VM y no se puede cambiar```**Tener especial atencin a los strings**, ya que dos strings con el mismo contenido pueden ser iguales pero no idnticos, dependiendo de las estrategias de optimizacin de la VM. Siempre es conveniente utilizar ==, que adems se puede modificar.# Mtodos avanzados## Obligatoriedad del return en mtodosPor lo general, los mtodos devuelven la ltima expresin que contienen. Pero a veces es necesario cortar el flujo de envo de mensajes, como por ejemplo aqu:```scaladef gradoDeFelicidad() { if (!esFeliz) { return 0 } ... clculo complejo ...}```Para determinar el grado de felicidad de alguien, tenemos como precondicin que sea feliz. Y para simplificar la definicin, escribimos el `if` y forzamos el return (dado que escribir nicamente `0` no tendr efecto, porque Xtend seguir evaluando el resto de las expresiones hasta terminar la ltima y nosotros queremos justamente cortar el flujo).En el caso de un mtodo que solo busque producir un efecto (`void`), es necesario utilizar `return;` con punto y coma...```scaladef metodoConEfecto() { ... cambios ... if (!situacion) { return; } ... otros cambios ...}```Igualmente, siempre es preferible tratar de extraer mtodos ms pequeos para simplificar la lgica.## Extension methodsUna de las herramientas ms poderosas consiste en definir **extension methods**. Supongamos que un negocio tiene un horario de apertura y de cierre y queremos saber, dada una hora, si est abierto.```scalaclass Negocio { int horarioApertura int horarioCierre def estaAbierto(int horaActual) { horaActual.between(horarioApertura, horarioCierre) }}```Por supuesto, no compila. No existe el mtodo between asociado a los enteros. Pero en otro archivo vamos a definir un mtodo esttico (no asociado a un objeto):```scalaclass NumberUtils { static def between(int num, int from, int to) { num >= from && num `, algo muy til cuando estamos instanciando objetos:```scalaval ventaNacional = new Venta => [ cantidadKilos = 12 fechaVenta = new Date parcela = parcela50 comprador = new CompradorNacional]```De esta manera, todos los mensajes se apuntan al objeto que resulta de evaluar la expresin `new Venta`, y simplifica el envo de mensajes: ```scalaventaNacional.cantidadKilos = 12ventaNacional.fechaVenta = new DateventaNacional....```## Links relacionados* [Colecciones](https://docs.google.com/document/d/1lzOStySb8i94oVvZUIxkgymf2tuCDuXzqSTnClPqKSM/edit?usp=sharing)* [Intro a manejo de errores con excepciones](https://docs.google.com/document/d/1G0a9j-OA0rIEA5cdvEhIMbztJVo86ssvZKBK8HL9akg/edit?usp=sharing)* [Ejercicio del Monedero](https://docs.google.com/document/d/1vVW91adl0p-NxGNpe8fqmC_5YmBkrxaLDFKyZ0xZb9Y/edit?usp=sharing) para ver cmo interactan la UI y el dominio a partir de errores del dominio y del sistema* [Testing](https://docs.google.com/document/d/11mVR-4wEZhlQMDEqrfQeYLypEsrSqXv98dr78SA0Oq4/edit?usp=sharing)" + +} , + +{ + +"title" : "Preparacion de un entorno de desarrollo xtend", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/xtend-preparacion-de-un-entorno-de-desarrollo.html", +"date" : "", +"content" : "# Download e instalacin base## Git Bash (slo para Windows)Para simplificar el uso de Git en entornos Windows, existe la herramienta **Git Bash** que pods descargar a partir de [esta pgina](https://gitforwindows.org/), haciendo click en el link "Download".Si ests en Mac o Linux, pods saltear este paso.## JDK: Java Development KitPrimero instalaremos el compilador de Java.Ingresamos a [esta direccin](https://jdk.java.net/java-se-ri/11), y descargamos la **Open JDK 11**, que es la versin oficial que manejamos desde 2020 y cuya licencia es [GPL](https://es.wikipedia.org/wiki/GNU_General_Public_License). ### Pasos de instalacinUna vez descargado el binario en una carpeta (supongamos que es `C:&#92;jdk11`), hay que configurar dos variables de entorno de tu sistema operativo:- JAVA_HOME: tiene que apuntar a `C:&#92;jdk11`)- PATH: hay que incorporarle `C:&#92;jdk11&#92;bin` (cuidando de no borrar lo que ya est)Te dejamos [un video que explica cmo hacerlo para Windows](https://www.youtube.com/watch?v=Cr_mwn67kFs) (el procedimiento es similar para MacOS / Linux)### Chequeos posteriores a la instalacin- Dentro de las variables de entorno de tu sistema operativo debe estar JAVA_HOME asignada. En Linux / Mac esto es `env | grep JAVA_HOME`, y en Windows `SET JAVA_HOME`. **Si la variable no est seteada, eso significa que te salteaste un paso, lo mismo si la carpeta que muestra JAVA_HOME no es la que contiene la versin que vos descargaste**. En ese caso volv al punto anterior y segu nuevamente las instrucciones para encontrar lo que est faltando. - En una ventana de lnea de comandos, verificar la versin de java instalada con `java -version`, y el compilador mediante `javac -version`. En ambos casos mostrar la versin por defecto para tu mquina. **Si no aparece la versin que descargaste, el sistema operativo asume por defecto otra instalacin, que podra ser incluso de una JRE (ver ms abajo)**. En ese caso, revis el link del punto anterior para ver qu puede estar faltando y repet los pasos.### JDK s, JRE no> **IMPORTANTE:** tens que instalar una JDK, no una JRE (Java Runtime Environment) que solo te permite ejecutar programas Java ya compilados. Para saber si tens una JDK, deberas ir al directorio de instalacin y en la carpeta `bin` debe estar un programa llamado `javac`, que es el compilador de Java.![image](/img/languages/jdkVsJre.png)Si no tens ese programa, no vas a poder pasar tus objetos a cdigo ejecutable en el entorno Xtend: la solucin es muy simple, descarg e instal una JDK. Para ms informacin te recomendamos [esta pgina](jdkVsJre.html)## EclipseNuestro entorno integrado de desarrollo (IDE) permite que en una misma herramienta editemos nuestro cdigo fuente, compilemos, hagamos pruebas, y muchas cosas ms. En Algoritmos 1 ya conociste Eclipse, con un entorno modificado especialmente para soportar el lenguaje Wollok. Aqu lo utilizaremos con diferentes plugins, pero seguramente te resultar familiar la forma de trabajar.### Pasos de instalacinTens que descargarlo desde [esta pgina](https://www.eclipse.org/downloads/) utilizando el link ms reciente de Eclipse (al 01/03 es **Get Eclipse IDE 202012**)> **NOTA:** pods visitar [la pgina histrica de descarga de Eclipses anteriores](https://wiki.eclipse.org/Older_Versions_Of_Eclipse) por si hay versiones ms nuevas y te interesa usar la versin 2020-12 que es con la que desarrollamos los ejemplos. Normalmente las actualizaciones de Eclipse siguen funcionando sin mayores problemas con el plugin de Xtend, Java y Maven.Eso te descarga un eclipse-installer, que es el primer paso. Lo abrs con un doble click, y luego seleccions- si ests cursando Programacin con Herramientas Modernas: "Eclipse IDE for Enterprise Java Developers"- cualquier otra cursada: "Eclipse for Java Developers", seleccionando la carpeta de destino.### Chequeos de instalacinUna vez que lo hayas descomprimido en una carpeta, pods hacer un acceso directo al `eclipse` o `eclipse.exe` y ejecutarlo con doble click. Necesitars definir un espacio de trabajo o _workspace_, que es la carpeta donde vas a ubicar todos tus proyectos.### Configuraciones adicionalesPor lo general no es necesario hacer nada ms, pero en caso de necesitarlo, en la carpeta raz donde descargaste el Eclipse vas a encontrar un archivo `eclipse.ini` que permite configurarf- cul es la versin de Java requerida (por defecto es 1.11 y no debera ser necesario modificarla)- cul es la ubicacin donde est el ejecutable de Java: es importante que apunte a una JDK y no a una JRE, como hemos comentado en la instalacin de la JDK. Si por defecto instalaste una JRE, tu Eclipse no ser capaz de compilar, recomendamos volver a la pgina JDK y reinstalar Java. De la misma manera, la JDK a la que apunte Eclipse debera ser la misma que vos instalaste: asegurate de que estn sincronizadas.A continuacin te dejamos un archivo `.ini` de ejemplo, ignorando las primeras lneas:```ini...--launcher.appendVmargs-vm/usr/lib/jvm/java-11-openjdk-amd64/bin-vmargs-Dosgi.instance.area.default=@user.home/eclipse-workspace-XX:+UseG1GC-XX:+UseStringDeduplication--add-modules=ALL-SYSTEM-Dosgi.requiredJavaVersion=1.11-Dosgi.dataAreaRequiresExplicitInit=true-Xms512m-Xmx1768m--add-modules=ALL-SYSTEM-Declipse.p2.max.threads=10-Doomph.update.url=http://download.eclipse.org/oomph/updates/milestone/latest-Doomph.redirection.index.redirection=index:/->http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/```En el ejemplo estamos configurando una memoria inicial de 512 MB y una memoria mxima de 1768 MB, una JDK 1.11 requerida. El resto son valores por defecto que te va a crear el instalador de Eclipse.## MavenSegu los pasos de instalacin de [esta pgina](guia-de-instalacion-de-maven.html)## Plugin XtendInstal el plugin de Xtend desde el Update Site, siguiendo estos pasos:- En el men de Eclipse, Help > Install New Software ... botn Add- En la ventana de dilogo Add Repository, en el nombre escribir algo como "Xtend Plugin" y en Location copiar esta URL: [http://download.eclipse.org/modeling/tmf/xtext/updates/milestones/](http://download.eclipse.org/modeling/tmf/xtext/updates/milestones/)- A partir del 2021 se estar usando la versin **2.25**, en caso de que vayan saliendo nuevas versiones, se puede elegir qu versin instalar destildando la opcin "Show only the latest versions of available software" (ms abajo est resaltado en la imagen). En caso de duda sobre qu versin instalar, aconsejamos consultar por la lista de difusin al docente responsable.- Seleccionar el check Xtext, y luego Xtend IDE, hacer click en Next y luego en Finish![image](/img/wiki/Xtend-installation-2020-2.png)- Reiniciar el Eclipse# Configuraciones default del eclipseAntes que nada cheque las [Configuraciones generales para cualquier Eclipse](configuraciones-generales-para-cualquier-eclipse.html)# Cmo empezar?- Crear un proyecto Maven (si no instalaste Maven hacelo como se sugiere [aqu](guia-de-instalacion-de-maven.html) - en la primera ventana, clickear en la opcin "Create a simple project (Skip archetype selection)", luego Next... - definir un groupId, que puede ser el *materia* . Ej: algo2, phm, etc. - definir un artifactId, que se asocia al nombre de tu proyecto- Para definir el archivo `pom.xml` de Maven con el que vas a configurar tu proyecto, pods basarte en el modelo de ejemplo de [esta pgina](xtend-creacion-proyecto.html) # Tips- Para que cuando hagas New > File te aparezcan las clases y las interfaces Xtend, Window > Customize Perspective... > solapa Menu Visibility > expands File > New > y seleccions las de Xtend (Xtend class, inteface, annotation y enum).# Documentacin- [Documentacin oficial](http://www.eclipse.org/xtend/documentation/)# Links tiles- [Siguiente paso: Creacin de un proyecto en Xtend](xtend-creacion-proyecto.html)- [Volver al men principal del entorno Xtend](xtend-principal.html)" + +} , + +{ + +"title" : "Xtend - pagina principal", +"category" : "", +"tags" : "", +"url" : "/wiki/articles/xtend-principal.html", +"date" : "", +"content" : "![image](/img/languages/Xtend.png)A continuacin te vamos a dejar los pasos de instalacin del entorno Xtend para las materias Algoritmos 2, Algoritmos 3 y Programacin con Herramientas Modernas. Segu metdicamente los puntos y no saltees las verificaciones para asegurarte que en tu mquina tengas todas las herramientas necesarias para trabajar.* [Instalacin del entorno base](xtend-preparacion-de-un-entorno-de-desarrollo.html)* Configuracin del entorno * [Configuraciones default de Eclipse](configuraciones-generales-para-cualquier-eclipse.html)* Recomendaciones para trabajar en la materia * [Cmo generar un proyecto Xtend nuevo](xtend-creacion-proyecto.html) * [Sobre el control de versiones](xtend-amigandonos-git.html)* Ayudas para manejarte con el lenguaje * [Gua rpida de Xtend](xtend-guia-rapida.html) * [Colecciones](https://docs.google.com/document/d/1lzOStySb8i94oVvZUIxkgymf2tuCDuXzqSTnClPqKSM/edit?usp=sharing) * [Intro a manejo de errores con excepciones](https://docs.google.com/document/d/1G0a9j-OA0rIEA5cdvEhIMbztJVo86ssvZKBK8HL9akg/edit?usp=sharing) * [Ejercicio del Monedero](https://docs.google.com/document/d/1vVW91adl0p-NxGNpe8fqmC_5YmBkrxaLDFKyZ0xZb9Y/edit?usp=sharing) para ver cmo interactan la UI y el dominio a partir de errores del dominio y del sistema * [Testing](https://docs.google.com/document/d/11mVR-4wEZhlQMDEqrfQeYLypEsrSqXv98dr78SA0Oq4/edit?usp=sharing)" + +} , + +{ + +"title" : "Articles in &#8220;Java&#8221;", +"category" : "java", +"tags" : "", +"url" : "/categories/java/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +"title" : "Articles in &#8220;Enviroment&#8221;", +"category" : "enviroment", +"tags" : "", +"url" : "/categories/enviroment/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +"title" : "Articles in &#8220;Scala&#8221;", +"category" : "scala", +"tags" : "", +"url" : "/categories/scala/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +"title" : "Articles in &#8220;Haskell&#8221;", +"category" : "haskell", +"tags" : "", +"url" : "/categories/haskell/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +"title" : "Articles in &#8220;Python&#8221;", +"category" : "python", +"tags" : "", +"url" : "/categories/python/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +"title" : "Articles in &#8220;Ruby&#8221;", +"category" : "ruby", +"tags" : "", +"url" : "/categories/ruby/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +"title" : "Articles in &#8220;Dds&#8221;", +"category" : "dds", +"tags" : "", +"url" : "/categories/dds/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +"title" : "Articles in &#8220;Paradigmas&#8221;", +"category" : "paradigmas", +"tags" : "", +"url" : "/categories/paradigmas/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +"title" : "Articles in &#8220;Tadp&#8221;", +"category" : "tadp", +"tags" : "", +"url" : "/categories/tadp/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +"title" : "Articles in &#8220;Algo3&#8221;", +"category" : "algo3", +"tags" : "", +"url" : "/categories/algo3/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +"title" : "Articles in &#8220;Reliability_engineering&#8221;", +"category" : "reliability_engineering", +"tags" : "", +"url" : "/categories/reliability_engineering/", +"date" : "", +"content" : "Articles for category: {{ page.category | capitalize }} {% for article in site.pages %} {% if article.url contains 'wiki/articles/' %} {% for category in article.categories %} {% if category == page.category %} {{ article.title }} {% endif %} {% endfor %} {% endif %} {% endfor %} " + +} , + +{ + +} , + +{ + +} + +] \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000000..49db207ea3 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,1020 @@ + + + +/wiki/articles/FAQ.html + + +/wiki/articles/abstraccion.html + + +/wiki/articles/algo2-temario.html + + +/wiki/articles/algo3-temario.html + + +/wiki/articles/amigandonos-con-el-entorno-de-desarrollo.html + + +/wiki/articles/android-cambiar-icono.html + + +/wiki/articles/android-ciclo-de-vida.html + + +/wiki/articles/android-instalacion.html + + +/wiki/articles/android-introduccion.html + + +/wiki/articles/angular-instalacion.html + + +/wiki/articles/aplicacion-parcial.html + + +/wiki/articles/aplicacion.html + + +/wiki/articles/append-como--foldr-f-a-.html + + +/wiki/articles/arena-configuracion.html + + +/wiki/articles/arena-instalacion.html + + +/wiki/articles/aritmetica-en-prolog.html + + +/wiki/articles/arquitecturas.html + + +/wiki/articles/arrays-literales-en-smalltalk.html + + +/articles.html + + +/wiki/articles/ast-abstract-syntax-tree.html + + +/wiki/articles/atributos-de-calidad.html + + +/wiki/articles/backtracking.html + + +/wiki/articles/bagna-cauda.html + + +/wiki/articles/bajar-un-proyecto-maven-de-un-repositorio-git.html + + +/wiki/articles/bibliografia-sobre-programacion-avanzada-orientada-a-objetos.html + + +/wiki/articles/binding--polimorfismo-y-sobrecarga.html + + +/wiki/articles/bloques.html + + +/wiki/articles/brownies.html + + +/wiki/articles/c--.html + + +/wiki/articles/c.html + + +/wiki/articles/calculo-del-tipo-de-una-funcion-en-haskell.html + + +/wiki/articles/calidad-de-las-pruebas-unitarias.html + + +/wiki/articles/cannot-construct-the-infinite-type.html + + +/wiki/articles/cantidad-de-parametros-de-una-funcion-en-haskell.html + + +/wiki/internal/categories.html + + +/wiki/articles/ciclo-de-vida-de-un-objeto.html + + +/wiki/articles/clase-abstracta-vs-interfaces.html + + +/wiki/articles/clase-abstracta-vs-interfaz.html + + +/wiki/articles/clases-anonimas-en-java.html + + +/wiki/articles/clases-vs-instancias.html + + +/wiki/articles/clases.html + + +/wiki/articles/coeficiente-de-felicidad-docente.html + + +/wiki/articles/comidas.html + + +/wiki/articles/como-bajar-y-correr-un-ejemplo-en-wicket.html + + +/wiki/articles/como-crear-una-subclase-en-squeak.html + + +/wiki/articles/como-empezar.html + + +/wiki/articles/como-hacer-para-que-de-un-objeto-muestre-lo-que-yo-quiero.html + + +/wiki/articles/como-hacer-predicados-de-orden-superior.html + + +/wiki/articles/composicion--oop-.html + + +/wiki/articles/composicion.html + + +/wiki/articles/comunicacion.html + + +/wiki/articles/concepto-de-funcion.html + + +/wiki/articles/conceptos-basicos-del-diseno.html + + +/wiki/articles/conceptos-de-ingenieria-de-software-y-de-sistemas.html + + +/wiki/articles/configuracion-de-maven-para-poder-utilizar-las-herramientas-de-uqbar.html + + +/wiki/articles/configuraciones-generales-para-cualquier-eclipse.html + + +/wiki/articles/conocimiento-de-dominio-y-refactoring.html + + +/wiki/articles/creacion-de-objetos--con-parametros.html + + +/wiki/articles/creacion-de-un-proyecto-maven-basico.html + + +/wiki/articles/crear-un-proyecto-en-xp-dev.html + + +/wiki/articles/css.html + + +/wiki/articles/cual-es-la-diferencia-entre-una-tupla-y-una-lista-.html + + +/wiki/articles/cuando-usar-parentesis.html + + +/wiki/articles/cuestiones-basicas-para-resolver-el-parcial-de-objetos.html + + +/wiki/articles/currificacion.html + + +/wiki/articles/data--definiendo-nuestros-tipos-en-haskell.html + + +/wiki/articles/declaratividad-vs--expresividad.html + + +/wiki/articles/declaratividad.html + + +/wiki/articles/definiciones-locales--where-.html + + +/wiki/articles/deploy-en-maven-central.html + + +/wiki/articles/deploys-componentes-de-dominio-uqbar.html + + +/wiki/articles/desafio--construir-esta-sucesion.html + + +/wiki/articles/desafio--find-con-notacion-point-free.html + + +/wiki/articles/desafio--hacer-que-un-data-propio-sea-enum.html + + +/wiki/articles/desafio--ordenar-con-arbol-b.html + + +/wiki/articles/desafio--piramide-de-numeros.html + + +/wiki/articles/desafio--suma-de-distancias.html + + +/wiki/articles/desafio--suma-par.html + + +/wiki/articles/desafio--triada-uqbariana.html + + +/wiki/articles/desafios-cafe-con-leche.html + + +/wiki/articles/design-temario.html + + +/wiki/articles/diagrama-de-clases.html + + +/wiki/articles/diccionarios.html + + +/wiki/articles/diferencia-entre-objetos-y-procedural---con-un-ejercicio-de-la-guia-1.html + + +/wiki/articles/diferencias-entre-polimorfismo--abstraccion-y-encapsulamiento.html + + +/wiki/articles/diseno-iterativo.html + + +/wiki/articles/diseno-y-sistemas-de-tipos.html + + +/wiki/articles/diseno-y-tecnologia.html + + +/wiki/articles/distinct.html + + +/wiki/articles/dont-cross-the-beams.html + + +/wiki/articles/double-dispatch.html + + +/wiki/articles/dsl.html + + +/wiki/articles/efectos-y-diseno.html + + +/wiki/articles/el-papel-del-diseno-en-la-metodologia-de-desarrollo.html + + +/wiki/articles/el-signo-pesos-en-haskell.html + + +/wiki/articles/elementos-teoricos-para-comparar-tecnologias-de-presentacion.html + + +/wiki/articles/encapsulamiento.html + + +/wiki/articles/entradas-al-proceso-de-diseno.html + + +/wiki/articles/errores-comunes--usar-un-predicado-como-si-fuera-una-variable.html + + +/wiki/articles/errores-comunes-al-comenzar-a-trabajar-con-haskell.html + + +/wiki/articles/errores-comunes-con-select--y-collect-.html + + +/wiki/articles/errores-comunes.html + + +/wiki/articles/errores-en-haskell.html + + +/wiki/articles/errores-frecuentes-al-programar-en-logico.html + + +/wiki/articles/escribiendo-un-paper.html + + +/wiki/articles/esquemas-de-tipado.html + + +/wiki/articles/estado--identidad-y-diseno.html + + +/wiki/articles/estado-y-diseno.html + + +/wiki/articles/estereotipos-de-objetos.html + + +/wiki/articles/estrategias-de-evaluacion.html + + +/wiki/articles/evaluacion-diferida-y-diseno.html + + +/wiki/articles/excepciones-avanzadas.html + + +/wiki/articles/excepciones.html + + +/wiki/articles/expresiones-lambda.html + + +/wiki/articles/expresividad.html + + +/wiki/internal/featured_article.html + + +/wiki/articles/fideos.html + + +/wiki/articles/flattening-vs-linearization.html + + +/wiki/articles/fold.html + + +/wiki/articles/formato-de-un-paper.html + + +/wiki/articles/frases-teadepeanas.html + + +/wiki/articles/funciones-por-partes.html + + +/wiki/articles/function-object.html + + +/wiki/articles/garbage-collector.html + + +/wiki/articles/git--un-versionador-distribuido.html + + +/wiki/articles/gradle.html + + +/wiki/articles/groovy-vs-scala.html + + +/wiki/articles/guia-de-instalacion-de-maven.html + + +/wiki/articles/guia-de-instalacion-de-rails.html + + +/wiki/articles/guia-de-instalacion-de-ruby.html + + +/wiki/articles/guiso-de-lentejas.html + + +/wiki/articles/herencia.html + + +/wiki/articles/herramientas-de-desarrollo-con-android.html + + +/wiki/articles/herramientas-de-instanciacion.html + + +/wiki/articles/herramientas-utiles.html + + +/wiki/articles/high-order-functions-and-variational-calculus.html + + +/wiki/articles/home.html + + +/wiki/articles/html.html + + +/wiki/articles/hugs-trex-insertfield-not-in-scope.html + + +/wiki/articles/igual-o-identico-----vs---.html + + +/ + + +/wiki/articles/inferencia-de-tipos.html + + +/wiki/articles/inject-into-.html + + +/wiki/articles/inmutabilidad.html + + +/wiki/articles/intro-a-colecciones.html + + +/wiki/articles/introduccion-a-las-metodologias-de-desarrollo-de-software.html + + +/wiki/articles/java.html + + +/wiki/articles/javascript.html + + +/wiki/articles/jdkVsJre.html + + +/wiki/articles/json.html + + +/wiki/articles/juegos-de-estrategia.html + + +/wiki/articles/kotest-testeo-unitario-avanzado.html + + +/wiki/articles/kotlin-amigandonos-git.html + + +/wiki/articles/kotlin-bajar-un-proyecto-gradle-de-un-repositorio-git.html + + +/wiki/articles/kotlin-ci.html + + +/wiki/articles/kotlin-creacion-proyecto.html + + +/wiki/articles/kotlin-guia-rapida.html + + +/wiki/articles/kotlin-preparacion-de-un-entorno-de-desarrollo.html + + +/wiki/articles/kotlin-principal.html + + +/wiki/articles/lambdas-en-java-8.html + + +/wiki/articles/lectura-de-un-paper.html + + +/wiki/articles/lenguajes-del-paradigma-logico.html + + +/wiki/articles/lenguajes-especificos-de-dominio.html + + +/wiki/articles/lenguajes-para-centrales-nucleares.html + + +/wiki/articles/lenguajes.html + + +/wiki/articles/ley-de-demeter.html + + +/wiki/articles/libreria-y-framework.html + + +/wiki/articles/lista-de-proyectos.html + + +/wiki/articles/listas-por-comprension.html + + +/wiki/articles/locro.html + + +/wiki/articles/logico---trabajo-con-valores.html + + +/wiki/articles/lombardizacion.html + + +/wiki/articles/macros-scala.html + + +/wiki/articles/manejo-de-booleanos-en-haskell.html + + +/wiki/articles/manejo-de-booleanos-en-smalltalk.html + + +/wiki/articles/manejo-de-booleanos.html + + +/wiki/articles/manejo-de-errores.html + + +/wiki/articles/manejo-de-memoria-en-c.html + + +/wiki/articles/maquina-virtual.html + + +/wiki/articles/masa-de-pizza.html + + +/wiki/articles/maven.html + + +/wiki/articles/mejorar-la-experiencia-del-pharoer.html + + +/wiki/articles/mensajes-de-colecciones.html + + +/wiki/articles/mensajes-y-metodos.html + + +/wiki/articles/metamodelo.html + + +/wiki/articles/metaprogramacion.html + + +/wiki/articles/method-lookup.html + + +/wiki/articles/method-missing.html + + +/wiki/articles/metodos-de-clase-para-crear-objetos-inicializados.html + + +/wiki/articles/min--y-max-.html + + +/wiki/articles/mixins.html + + +/wiki/articles/modelando-objetos---responsabilidades-y-delegacion.html + + +/wiki/articles/monada.html + + +/wiki/articles/no-hay-instancias-para-el-show.html + + +/wiki/articles/nombres-de-clases.html + + +/wiki/articles/normalizacion-en-objetos.html + + +/wiki/articles/notacion-point-free.html + + +/wiki/articles/npm-dependencias.html + + +/wiki/articles/objective-c.html + + +/wiki/articles/observer-en-pharo-smalltalk.html + + +/wiki/articles/oo-objetos-factory.html + + +/wiki/articles/oo-temporary-variable.html + + +/wiki/articles/orden-superior-y-diseno.html + + +/wiki/articles/orden-superior.html + + +/wiki/articles/otros-temas-interesantes-de-programacion.html + + +/wiki/articles/pagina-principal.html + + +/wiki/articles/palitos-de-queso.html + + +/wiki/articles/panqueques.html + + +/wiki/articles/paradigma-de-objetos---method-lookup.html + + +/wiki/articles/paradigma-de-objetos.html + + +/wiki/articles/paradigma-de-programacion.html + + +/wiki/articles/paradigma-funcional.html + + +/wiki/articles/paradigma-logico---casos-de-no-inversibilidad.html + + +/wiki/articles/paradigma-logico---como-pienso-la-resolucion-de-un-punto.html + + +/wiki/articles/paradigma-logico---conjuncion-y-disyuncion.html + + +/wiki/articles/paradigma-logico---detalles-del-swi-prolog.html + + +/wiki/articles/paradigma-logico---el-forall.html + + +/wiki/articles/paradigma-logico---existe-vs-para-todo.html + + +/wiki/articles/paradigma-logico---forall---no-siempre-con-member.html + + +/wiki/articles/paradigma-logico---functores.html + + +/wiki/articles/paradigma-logico---generacion.html + + +/wiki/articles/paradigma-logico---individuos-compuestos.html + + +/wiki/articles/paradigma-logico---individuos-simples.html + + +/wiki/articles/paradigma-logico---introduccion.html + + +/wiki/articles/paradigma-logico---inversibilidad.html + + +/wiki/articles/paradigma-logico---listas.html + + +/wiki/articles/paradigma-logico---multiples-respuestas.html + + +/wiki/articles/paradigma-logico---negacion.html + + +/wiki/articles/paradigma-logico---un-poco-de-nomenclatura.html + + +/wiki/articles/paradigma-logico.html + + +/wiki/articles/paradigmas-de-programacion.html + + +/wiki/articles/parsers-monadicos.html + + +/wiki/articles/patrones-de-comunicacion-entre-componentes.html + + +/wiki/articles/pattern-matching--polimorfismo-y-diseno.html + + +/wiki/articles/pattern-matching-en-haskell.html + + +/wiki/articles/pepita.html + + +/wiki/articles/pharo-para-programadores-ozonosos.html + + +/wiki/articles/phm-script-mapeo-manual-or.html + + +/wiki/articles/phm-script-mongodb.html + + +/wiki/articles/phm-temario.html + + +/wiki/articles/polimorfismo-en-el-paradigma-de-objetos.html + + +/wiki/articles/polimorfismo-en-el-paradigma-logico.html + + +/wiki/articles/polimorfismo-parametrico-y-ad-hoc.html + + +/wiki/articles/polimorfismo.html + + +/wiki/articles/portal-del-investigador.html + + +/wiki/articles/possibly-incorrect-indentation-or-mismatched-brackets.html + + +/wiki/articles/precedencia-de-los-operadores-mas-comunes-en-haskell.html + + +/wiki/articles/precedencia-de-mensajes.html + + +/wiki/articles/preguntas-frecuentes-del-paradigma-logico.html + + +/wiki/articles/preguntas-frecuentes.html + + +/wiki/articles/preparacion-de-un-entorno-de-desarrollo-groovy.html + + +/wiki/articles/preparacion-de-un-entorno-de-desarrollo-java-8.html + + +/wiki/articles/preparacion-de-un-entorno-de-desarrollo-java.html + + +/wiki/articles/preparacion-de-un-entorno-de-desarrollo-scala.html + + +/wiki/articles/problemas-comunes-con-los-tipos-numericos-de-haskell.html + + +/wiki/articles/prototipado-vs-clases.html + + +/wiki/articles/prototipado.html + + +/wiki/articles/pseudovariable.html + + +/wiki/articles/publicar-un-proyecto-en-svn.html + + +/wiki/articles/python.html + + +/wiki/articles/que-entendemos-por-programacion-orientada-a-objetos-.html + + +/wiki/articles/react-instalacion.html + + +/wiki/articles/recursividad-en-haskell.html + + +/wiki/articles/recursividad-en-logico.html + + +/wiki/articles/redefinicion.html + + +/wiki/articles/refactoring.html + + +/wiki/articles/reflection.html + + +/wiki/articles/relleno-caprese.html + + +/wiki/articles/relleno-dale.html + + +/wiki/articles/relleno-de-carne.html + + +/wiki/articles/representacion-de-informacion.html + + +/wiki/articles/resolver-problemas-de-dependencias-maven-dentro-de-eclipse.html + + +/wiki/articles/responsiveness.html + + +/wiki/articles/resumen-de-wicket--pros-y-contras.html + + +/wiki/articles/resumen-lenguajes-prototipados.html + + +/wiki/articles/robustez-de-los-lenguajes.html + + +/wiki/articles/ruby.html + + +/wiki/articles/sabores-de-colecciones.html + + +/wiki/articles/salsa-jack-daniel-s.html + + +/wiki/articles/scala.html + + +/wiki/articles/self---pseudovariable.html + + +/wiki/articles/self.html + + +/wiki/articles/sintaxis-de-smalltalk.html + + +/wiki/articles/smalltalk.html + + +/wiki/articles/sobre-el-uso-del-igual-----en-prolog.html + + +/wiki/articles/super.html + + +/wiki/articles/tecnicas-avanzadas-de-programacion.html + + +/wiki/articles/template-method.html + + +/wiki/articles/testeo-unitario-avanzado.html + + +/wiki/articles/testing.html + + +/wiki/articles/tipo-abstracto-de-datos.html + + +/wiki/articles/tipos-de-haskell.html + + +/wiki/articles/tipos-de-mensajes-en-smalltalk.html + + +/wiki/articles/tips-para-aprobar-un-parcial-de-funcional.html + + +/wiki/articles/tips-para-concursos-docentes.html + + +/wiki/articles/tips-para-la-resolucion-de-un-parcial-de-tadp.html + + +/wiki/articles/traits.html + + +/wiki/articles/transparencia-referencial--efecto-de-lado-y-asignacion-destructiva.html + + +/wiki/articles/ts-tipado.html + + +/wiki/articles/tutorial-de-squeak-y-pharo.html + + +/wiki/articles/tutorial-de-squeak.html + + +/wiki/articles/tutoriales-para-desarrollo-java.html + + +/wiki/articles/typeclasses.html + + +/wiki/articles/typedefs-y-tipos-anonimos.html + + +/wiki/articles/ui-arquitectura-general.html + + +/wiki/articles/ui-clasificacion.html + + +/wiki/articles/ui-definiciones-iniciales.html + + +/wiki/articles/ui-elementos-a-tener-en-cuenta-al-programar-ui.html + + +/wiki/articles/ui-mvcpesado-formas-de-vincular-una-vista-con-el-modelo-de-dominio.html + + +/wiki/articles/ui-mvcpesado-intro-mvc.html + + +/wiki/articles/ui-mvcpesado-mmvc.html + + +/wiki/articles/ui-mvcpesado-navegacion.html + + +/wiki/articles/ui-mvcpesado-transaccion.html + + +/wiki/articles/ui-mvcpesado-validaciones-errores.html + + +/wiki/articles/ui-web-intro-arquitectura.html + + +/wiki/articles/unexpected-----.html + + +/wiki/articles/unificacion-y-pattern-matching.html + + +/wiki/articles/uso-de-features-de-lenguajes-dinamicos.html + + +/wiki/articles/value-object.html + + +/wiki/articles/variables-locales-en-metodos.html + + +/wiki/articles/variables-y-metodos-de-clase.html + + +/wiki/articles/variables.html + + +/wiki/articles/warning--singleton-variables.html + + +/wiki/articles/xtend-amigandonos-git.html + + +/wiki/articles/xtend-creacion-proyecto.html + + +/wiki/articles/xtend-guia-rapida.html + + +/wiki/articles/xtend-preparacion-de-un-entorno-de-desarrollo.html + + +/wiki/articles/xtend-principal.html + + +/categories/java/ + + +/categories/enviroment/ + + +/categories/scala/ + + +/categories/haskell/ + + +/categories/python/ + + +/categories/ruby/ + + +/categories/dds/ + + +/categories/paradigmas/ + + +/categories/tadp/ + + +/categories/algo3/ + + +/categories/reliability_engineering/ + + diff --git a/wiki/articles/FAQ.html b/wiki/articles/FAQ.html new file mode 100644 index 0000000000..0b37f34b31 --- /dev/null +++ b/wiki/articles/FAQ.html @@ -0,0 +1,303 @@ + + + + + + + + + + + FAQ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + FAQ +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    FAQ

    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/abstraccion.html b/wiki/articles/abstraccion.html new file mode 100644 index 0000000000..bd3193febd --- /dev/null +++ b/wiki/articles/abstraccion.html @@ -0,0 +1,323 @@ + + + + + + + + + + + Abstraccion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Abstraccion +

    +
    + + + +
    +

    Programar implica muchas veces manejar grandes cantidades de información, un programa es una entidad muy compleja y por lo tanto es muy difícil abarcarlo en su totalidad. Por eso necesitamos herramientas que nos permitan manejar esa complejidad.

    + +

    Gran parte de esas ideas trabajan con el principio de “dividir y conquistar”, esto es, tomar una parte más pequeña del programa y poder comprenderla olvidándonos momentáneamente del resto del programa. Sin embargo, siempre que uno tome una parte de un programa más grande, esa parte tendrá relaciones con otras partes del sistema. Para entenderlo yo debo poder incorporar esas otras partes a mi análisis pero sin tener que comprender todos sus detalles. Las herramientas que nos permiten eso las denominamos abstracciones.

    + +

    Una abstracción es una forma de interpretar y conceptualizar lo que resulta más importante de una entidad compleja, sin tener que tener en cuenta todos sus detalles. Me permite quedarme con lo esencial descartando lo que (para mí, en ese momento) es accesorio.

    + +

    Una abstracción es un concepto o una idea que no está asociado a ningún caso concreto. Abstraer es formar una idea general a partir de casos particulares. En la vida cotidiana usamos abstracciones todo el tiempo y gracias a eso, por ejemplo, podemos saber que una mesa es una mesa más allá de si es cuadrada o redonda, de madera o de plástico, con 4, 3 o 6 patas. Cuando programamos también es importante encontrar buenas abstracciones.

    + +

    Cada uno de los paradigmas que vamos a aprender, nos va a brindar sus propias formas de abstracción. Las abstracciones de cada paradigma van a ser conceptos fundamentales en esta materia. Para los que vienen de programar estructurado, la forma de abstracción más conocida es el procedimiento. Un procedimiento permite tomar un conjunto de instrucciones y darles un nombre para poder utilizarla en otro contexto. Quien invoca el procedimiento se concentra en qué es lo que necesita resolver, el procedimiento es el que implementa el cómo se resuelve un determinado problema.

    + +

    La Declaratividad es una forma de abstracción muy poderosa, que nos permite describir el conocimiento relativo a un problema desentendiéndonos de los algoritmos necesarios para manipular esa lógica, que son provistos por el motor.

    + +

    Alto nivel y Bajo nivel

    + +

    Muchas veces se habla de lenguajes de alto y bajo nivel, términos que se refieren al nivel de abstracción de cada lenguaje. Esta clasificación no es un blanco y negro, sino que sirve para comparar entre diferentes lenguajes respecto a qué tan cercanas son sus abstracciones a la máquina (bajo nivel) o al programador (alto nivel).

    + +

    A Assembler (trabaja directamente con instrucciones de máquina y los registros de la computadora) podemos considerarlo como de más bajo nivel que C por ejemplo (que es un lenguaje que se compila a código de máquina y nos permite trabajar con procedimientos y estructuras complejas), sin embargo se puede ir más a bajo nivel que con Assembler (siempre hay unos y ceros más abajo) y más alto nivel que C (todos los lenguajes que usamos en la materia tienen estas características, un ejemplo de ello es que no necesitamos manejar nuestra propia memoria, existen mecanismos para ello sobre los cuales nos paramos).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/algo2-temario.html b/wiki/articles/algo2-temario.html new file mode 100644 index 0000000000..9d47d7b777 --- /dev/null +++ b/wiki/articles/algo2-temario.html @@ -0,0 +1,338 @@ + + + + + + + + + + + Temario de Algoritmos II + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Temario de Algoritmos II +

    +
    + + + +
    +

    Software

    + + + +

    Páginas

    + + + + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/algo2.build.gradle.kts b/wiki/articles/algo2.build.gradle.kts new file mode 100755 index 0000000000..21d32708f4 --- /dev/null +++ b/wiki/articles/algo2.build.gradle.kts @@ -0,0 +1,60 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.9.22" + jacoco +} + +group = "ar.edu.unsam.algo2" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +val mockkVersion = "1.13.9" +val kotestVersion = "5.8.0" + +dependencies { + implementation(kotlin("stdlib")) + testImplementation("io.mockk:mockk:${mockkVersion}") + testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion") + testImplementation("io.kotest:kotest-assertions-core:$kotestVersion") +} + +tasks.withType { + kotlinOptions { + freeCompilerArgs = listOf("-Xjsr305=strict") + jvmTarget = "21" + } +} + +tasks.withType { + useJUnitPlatform() +} + +tasks.test { + finalizedBy(tasks.jacocoTestReport) +} + +tasks.jacocoTestReport { + dependsOn(tasks.test) +} + +jacoco { + toolVersion = "0.8.11" +} + +tasks.jacocoTestReport { + reports { + xml.required.set(true) + csv.required.set(true) + html.outputLocation.set(layout.buildDirectory.dir("jacocoHtml")) + } +} + +tasks.register("runOnGitHub") { + dependsOn("jacocoTestReport") + group = "custom" + description = "$ ./gradlew runOnGitHub # runs on GitHub Action" +} diff --git a/wiki/articles/algo2.build.yml b/wiki/articles/algo2.build.yml new file mode 100755 index 0000000000..ff7d75191e --- /dev/null +++ b/wiki/articles/algo2.build.yml @@ -0,0 +1,94 @@ +# .github/workflows/build.yml +# Basado en la documentacion de GitHub Actions +# => https://docs.github.com/en/actions +name: build + +# "on" controla cuando se ejecuta la action. En este caso, dispara el workflow +# ante un evento de "push" o de "pull request", pero solo cuando ocurra +# en las ramas de nombre "main" o "master". Un PR a "develop", o un commit +# en un branch sin PRs orientados a esas dos que indicamos no lo activará. +on: + push: + branches: [master, main] + pull_request: + branches: [master, main] +# "jobs" describe los diferentes trabajos a realizar. +jobs: + # En esta ocasión tenemos uno solo, para buildear, testear y subir la info de coverage. + gradle-plus-coverage: + # "runs-on" es el encargado de correr el job. En nuestro caso una VM con ubuntu. + runs-on: ubuntu-latest + # "steps" enumera todos los pasos a seguir cuando se ejecute este job. + steps: + # Primero hacemos checkout a nuestro repo para que el job pueda acceder al mismo. + - name: Checkout Repo + # Para muchas funcionalidades, podemos aprovechar workflow pre-construidos mediante "uses" + uses: actions/checkout@v4 + + # Configuramos el Java apropiado en nuestro ubuntu. + - name: Set Up Java + uses: actions/setup-java@v4 + # "with" nos deja especificar parametros del action que importamos, tales como versión y distribución a usar. + with: + distribution: 'temurin' + java-version: '21' + + # También podemos ejecutar comandos de bash, mediante "run" + - run: | + chmod +x ./gradlew + + # Para buildear, testear y correr jacoco tenemos una meta de gradle, runOnGithub, agregada a nuestro proyecto. + - uses: gradle/actions/setup-gradle@v3 + with: + arguments: runOnGitHub + + # runOnGitHub, mediante jacoco, genera reportes de cobertura en distintos formatos (html, csv, lcov, entre otros). + # Con el reporte en formato csv generamos una imagen svg que publica el % de código cubierto por los tests. + # Cabe aclarar que esto se crea en el ubuntu de GH Actions (donde corre el CI), pero no se encuentra en el repositorio (todavía). + - name: Generate JaCoCo Badge + uses: cicirello/jacoco-badge-generator@v2 + with: + badges-directory: .github/badges + generate-coverage-badge: true + coverage-badge-filename: jacoco.svg + jacoco-csv-file: build/reports/jacoco/test/jacocoTestReport.csv + + # Para persistir el badge de cobertura que generamos, podemos hacer un push a la rama desde el ubuntu. + # Siendo ejecutado "por github mismo", tendrá permiso para commitear. + - name: Commit and push badge + # Mediante "if" restringimos para no hacer este paso en un pull request, de forma tal que no se persista + # el cambio en la medalla tras cada push a la rama final, hasta mergear definitivamente los cambios. + if: ${{ github.event_name != 'pull_request' }} + run: | + cd .github/badges + if [[ `git status --porcelain *.svg` ]]; then + git config --global user.name 'github-actions' + git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com' + git add *.svg + git commit -m "Autogenerated JaCoCo coverage badge" *.svg + git push + fi + + # ¡Pero en un PR podemos comentar la cobertura! Haremos el chequeo inverso para cubrirlo + - name: Post coverage summary in PR + if: ${{ github.event_name == 'pull_request' }} + uses: madrapps/jacoco-report@v1.6 + with: + paths: ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml + token: ${{ secrets.GITHUB_TOKEN }} + title: Estado Actual de Cobertura + + # Finalmente, subimos un artefacto con el reporte de jacoco en formato HTML. + # Estos archivos quedarán disponibles para descargar y revisar en Github durante un tiempo, y luego se borrarán. + - name: Upload Jacoco coverage report + uses: actions/upload-artifact@v4 + with: + name: jacoco-report + path: build/jacocoHtml/ + +# # Opcional: Podríamos subir nuestro reporte a un servicio como codecov. +# - name: Send JaCoCo reports to CodeCov +# run: | +# curl -Os https://uploader.codecov.io/latest/linux/codecov +# chmod +x codecov +# ./codecov -t ${{ CODECOV_TOKEN }} \ No newline at end of file diff --git a/wiki/articles/algo2.gitignore b/wiki/articles/algo2.gitignore new file mode 100644 index 0000000000..440d8d22d7 --- /dev/null +++ b/wiki/articles/algo2.gitignore @@ -0,0 +1,52 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties diff --git a/wiki/articles/algo3-temario.html b/wiki/articles/algo3-temario.html new file mode 100644 index 0000000000..0f3f6d9ecb --- /dev/null +++ b/wiki/articles/algo3-temario.html @@ -0,0 +1,590 @@ + + + + + + + + + + + Temario de Algoritmos III + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Temario de Algoritmos III +

    +
    + + + +
    +

    El sitio oficial de la materia es http://algo3.uqbar-project.org

    + +

    Unidad 1 - Introducción a las UI

    + + + +

    Unidad 2 - Web Estático

    + +

    Entorno

    + +

    Solo necesitás un editor de texto (nosotros te recomendamos Visual Studio Code) y un navegador (el que vos prefieras)

    + +

    Artículos

    + + + +

    Material

    + + + +

    Unidad 3 - Web Client Side MVC.

    + +

    Entorno

    + + + +

    Material

    + + + +

    Unidad 4 - Web Client Side FRP.

    + +

    Entorno

    + + + +

    Material

    + + + +

    Anexo A - Cliente pesado. MVC. (deprecado)

    + +

    Este anexo fue deprecado a partir del año 2020. Dejamos el material por razones históricas.

    +

    Contenidos principales

    + +

    En esta unidad se verán los conceptos principales que permiten organizar el diseño de una interfaz de usuario. Estos conceptos pueden resumirse en:

    + + + +

    Material de lectura complementario

    + + + +

    Entorno

    +
      +
    • Guía de Componentes
    • +
    • Bindings y demás controllers. Binding avanzado
    • +
    • Layouts
    • +
    • Navegación y manejo del estado
    • +
    • Manejo de Transacciones
    • +
    • Qué pasa cuando no tenemos binding
    • +
    + +

    Ejemplos en Internet

    + + + +

    Anexo B - Aplicaciones móviles

    + +

    Entorno

    + + + +

    Material

    + + + +

    Ejemplos

    + +

    Kotlin

    + + + +

    Java

    + +

    Podés hacer esta búsqueda en los repositorios de la organización Uqbar

    + +

    Ionic

    + +
      +
    • Carga de Productos: se integra con el reconocedor de código de barras del celular.
    • +
    • TODO List o lista de cosas para hacer, versión histórica en Ionic 1
    • +
    + +

    Ejemplos de Internet

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/amigandonos-con-el-entorno-de-desarrollo.html b/wiki/articles/amigandonos-con-el-entorno-de-desarrollo.html new file mode 100644 index 0000000000..aab93e737e --- /dev/null +++ b/wiki/articles/amigandonos-con-el-entorno-de-desarrollo.html @@ -0,0 +1,445 @@ + + + + + + + + + + + Amigandonos con el entorno de desarrollo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Amigandonos con el entorno de desarrollo +

    +
    + + + +
    +

    Algunas buenas prácticas para tener en cuenta:

    + +

    Control de versiones

    + +
      +
    • No todos los archivos deben subirse al repo. Como regla general no deberían subir archivos que se puedan generar a partir de otros, por ejemplo: +
        +
      • los binarios que se generan a partir del código fuente de ustedes. Ocupan espacio en el repositorio y se corre el riesgo de estar trabajando con versiones desactualizadas.
      • +
      • archivos de configuración propios de cada uno (por ejemplo el .settings que genera el Eclipse). Si alguno tiene una configuración diferente (que es muy muy muy probable) la van a estar pisando a cada rato, e incluso es probable que les genere conflictos.
      • +
      +
    • +
    + + + +
      +
    • Nunca deberían subir nuevos fuentes al repositorio sin explicar brevemente qué cambiaron. Si los mensajes son descriptivos (y “fix”, “asdsadsa” o “arreglo una cosita” definitivamente no lo son) rápidamente puedo detectar qué modificaron mis compañeros con sólo leer lo que escribieron en los commits. Una buena descripción me ayuda también a entender qué es lo que se modificó y por qué razón, especialmente útil a la hora de solucionar un conflicto o entender por qué se rompieron los tests.
    • +
    + + + +
      +
    • Establecer criterios de trabajo en grupo, algunos muy usados: +
        +
      • los tests tienen que estar en verde
      • +
      • los tests son de todos y todos somos responsables por mantenerlos
      • +
      • si encontramos un bug y no había un test que lo probaba agregamos uno
      • +
      • los tests son rápidos de correr
      • +
      +
    • +
    + + + +
      +
    • Establecer formas de trabajo y organizar el trabajo nuestro con el de los demás: +
        +
      • Cuando empiezo el día primero sincronizo el repositorio para ver los cambios que no tengo en el código
      • +
      • Acepto los cambios entrantes y en caso de ser necesario resuelvo conflictos
      • +
      • Corro los tests y veo que todo anda sobre ruedas
      • +
      • Vuelvo a sincronizar y veo que ya no quedan ni conflictos ni cambios sin aceptar
      • +
      • Subo mis cambios al repositorio remoto para que mis compañeros lo vean
      • +
      +
    • +
    + +

    Esto mismo lo hacemos varias veces al día y antes de subir algo nuevo al repositorio. Siempre corro los tests y si alguno da error, bueno, alguien subió algo indebido. Los tests y el repositorio nos ayudan a entender cuándo se rompió y por qué.

    + + + +

    Git

    + +
      +
    • A la hora de ignorar archivos, git nos provee una forma muy sencilla y a la vez poderosa de hacerlo: los .gitignore. Estos son archivos que podemos crear en cualquier carpeta de nuestra estructura (usualmente en el directorio raíz) y especificar en ellos qué archivos o patrones deberían quedar fuera del versionado. Cada línea del .gitignore representa algo que queremos ignorar, por ejemplo “enunciado.pdf” nos ignoraría ese archivo, mientras que “*.class” va a ignorar todos los .class que tengamos en el directorio actual y en todos sus subdirectorios. Pueden encontrar versiones de .gitignore para la mayoría de los lenguajes en https://github.com/github/gitignore
    • +
    + +

    A continuación te damos una lista de posibles recursos que deberían estar en el archivo .gitignore:

    + +
      +
    • /target/
    • +
    • .classpath
    • +
    • .project
    • +
    • bin
    • +
    • generated*
    • +
    • .settings
    • +
    + +

    Eclipse

    + +
      +
    • Cómo organizar los archivos: Convention Over Configuration, el código productivo debería estar en src/main y el código de test en src/test. ¿Qué gano usando estas convenciones? Me corren los tests, me integro con el mundo y eventualmente puedo usar herramientas externas sin tener que configurar nada, ya que respetan estas convenciones (como Maven).
    • +
    + + + +
      +
    • ¡Formatear el código! Nunca nos olvidemos de que nuestro código tiene que ser entendible para el resto de la humanidad. Además, el Eclipse lo hace solo (Ctrl + Shift + F).
    • +
    + + + +
      +
    • Utilización de packages (paquetes). Es una buena práctica agrupar las clases afines en paquetes para organizar semánticamente el código. No hay una guía firme a seguir con respecto a cómo organizar nuestro código, ya que suele depender del contexto en el cuál estamos trabajando, pero es muy común respetar convenciones para mantener la simplicidad y flexibilidad ahorrando al desarrollador de tomar estas decisiones (“Convention over Configuration”).
    • +
    + +

    Por ejemplo, en un proyecto completo tener paquetes para el “dominio”, “controllers” y “vista” (si correspondiese) es una convención común. Cada uno de éstos agrupa las clases que tienen un concepto afín. Se podría seguir ahondando en la definición de subpaquetes agrupando, por ejemplo, por componente:

    + +
    domain/
    +   ├── home
    +   ├── registration
    +   │   ├── Profile.java
    +   │   └── User.java
    +   └── settings
    +       ├── CustomPrivacy.java
    +       ├── DefaultPrivacy.java
    +       ├── Privacy.java
    +       └── Setting.java
    +
    +
    + +

    De esta manera, logramos mayor granularidad en la organización de nuestras clases.

    + +

    Otro uso de los paquetes, también relacionado con el concepto anteriormente mencionado Convention over Configuration, es el de identificar unívocamente a una aplicación. ¿Qué significa ésto? Que las clases que yo defina formen parte de un meta grupo que los identifique, y así evitar colisiones en los nombres que yo les ponga. Por ejemplo: yo puedo definir la clase Color, pero la api de Java AWT ya define una clase Color.

    + +

    Es por este motivo que se utiliza el dominio de internet de la organización, pero “dado vuelta”. Por ejemplo si trabajamos para Google sería común encontrar paquetes del estilo com.google.blah. Para el ejemplo de Color, la api de Java la define como java.awt.Color. En nuestro caso podríamos usar, por ejemplo: ar.edu.materiaQueCursan.paquete.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/android-cambiar-icono.html b/wiki/articles/android-cambiar-icono.html new file mode 100644 index 0000000000..12007ad9a0 --- /dev/null +++ b/wiki/articles/android-cambiar-icono.html @@ -0,0 +1,457 @@ + + + + + + + + + + + Android - cómo cambiar ícono y título de la app + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Android - cómo cambiar ícono y título de la app +

    +
    + + + + + +
    +

    Objetivo

    + +

    Por defecto cuando creamos desde cero una actividad en blanco (Blank Activity) con el Android Studio, nos genera la página con una toolbar que muestra el label de la aplicación.

    + +

    Android - Main Activity

    + +

    Vista Default

    + +

    La actividad principal define una toolbar

    + +
    <android.support.design.widget.AppBarLayout
    +  android:id="@+id/app_bar"
    +  android:layout_width="match_parent"
    +  android:layout_height="wrap_content"
    +  android:theme="@style/AppTheme.AppBarOverlay">
    +
    +  <LinearLayout
    +    android:layout_width="match_parent"
    +    android:layout_height="wrap_content">
    +
    +    <android.support.v7.widget.Toolbar
    +      android:id="@+id/toolbar"
    +
    + +

    El id/toolbar se asigna en el método onCreate() al heredar de AppCompatActivity:

    + +
    override fun onCreate(savedInstanceState: Bundle?) {
    +  super.onCreate(savedInstanceState)
    +  setContentView(R.layout.activity_pelicula_app_bar)
    +
    +  val toolbar = findViewById(R.id.toolbar) as Toolbar
    +  setSupportActionBar(toolbar)
    +
    + +

    En nuestro AndroidManifest.xml definimos el label de la aplicación, mediante una indirección a una constante:

    + +
    <activity
    +  android:name=".ConversorActivity"
    +  android:label="@string/app_name"
    +  >
    +
    + +

    Esa constante entonces, debemos verla en el archivo res/values/strings.xml:

    + +
    <resources>
    +  <string name="app_name">ConversorApp</string> 
    +
    + +

    Cambiando el título

    + +

    Primero lo más sencillo: cambiaremos el nombre de la aplicación.

    + +
    <resources>
    +  <string name="app_name">Conversor de medidas</string>
    +
    + +

    Otra opción es definir una nueva constante y apuntar la propiedad android:label de la activity principal de nuestra aplicación hacia esta constante, en todo caso dejamos esta tarea al lector.

    + +

    Agregando un ícono a nuestra aplicación

    + +

    Si además queremos visualizar un ícono en la toolbar, debemos modificar el layout default

    + +
      +
    • la toolbar ahora debe incluir +
        +
      • una imagen
      • +
      • y un textview con tamaño de título
      • +
      +
    • +
    • y debemos redefinir la asignación heredada en el método onCreate
    • +
    + +

    Encontrar un ícono

    + +

    La imagen debe tener un ícono, hay algunas opciones

    + +
      +
    • construirlo nosotros mediante algún programa open-source
    • +
    • buscar un ícono de licencia libre en Internet
    • +
    + +

    Vamos por la segunda opción, ingresamos a esta página y seleccionamos , por ejemplo, esta URL: cambiamos el color de fondo y al hacer Download zip vemos que tenemos el mismo png con diferentes tamaños en directorios especiales, uno para cada tipo de resolución:

    + +

    Copiamos entonces el directorio res a nuestra aplicación:

    + +
      +
    1. abrimos el zip
    2. +
    3. extract …
    4. +
    5. … al directorio donde está la aplicación
    6. +
    + +

    Ahora sí generamos la ImageView y el TextView (activity_conversor.xml):

    + +
    <android.support.v7.widget.Toolbar
    +  android:layout_width="match_parent"
    +  android:layout_height="?attr/actionBarSize"
    +  android:background="?attr/colorPrimary"
    +  app:popupTheme="@style/AppTheme.PopupOverlay">
    +<ImageView 
    +  android:layout_width="wrap_content"
    +  android:layout_height="wrap_content"
    +  android:src="@drawable/ic_action" />
    +<TextView
    +  android:id="@+id/toolbar"
    +  android:layout_width="wrap_content"
    +  android:layout_height="wrap_content" />
    +</android.support.v7.widget.Toolbar>
    +
    + +

    Hicimos un pequeño cambio: el id/toolbar se lo asignamos al TextView en lugar de a la toolbar.

    + +

    Ejecutamos la aplicación y nos aparece un mensaje de error en el LogCat:

    + +
    11-10 15:21:52.540 8720-8720/? E/AndroidRuntime:  Caused by: java.lang.ClassCastException: android.support.v7.widget.AppCompatTextView cannot be cast to android.support.v7.widget.Toolbar
    +11-10 15:21:52.540 8720-8720/? E/AndroidRuntime:     at org.uqbar.conversor.ConversorActivity.onCreate(ConversorActivity.java:23)
    +
    + +

    Ajustamos entonces el método onCreate, para asignar manualmente el valor del textview (ConversorActivity.java):

    + +
    override fun onCreate(savedInstanceState: Bundle?) {
    +  super.onCreate(savedInstanceState)
    +  setContentView(R.layout.activity_pelicula_app_bar)
    +
    +  val toolbar = findViewById(R.id.toolbar) as Toolbar
    +  setSupportActionBar(toolbar)
    +  toolbar.text = R.string.app_name
    +
    + +

    Ahora sí, se visualiza el ícono y el título:

    + +

    Android New Title & Icon

    + +

    Pero sería bueno que resaltara un poco más el título, para eso configuramos la propiedad textSize:

    + +
    <TextView
    +  android:id="@+id/toolbar"
    +  android:layout_width="wrap_content"
    +  android:layout_height="wrap_content"
    +  android:textAppearance="?
    +  android:attr/textAppearanceLarge"/>
    +
    + +

    Resultado final

    + +

    Y vemos reflejado el cambio en la aplicación

    + +

    Android Resultado Final

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/android-ciclo-de-vida.html b/wiki/articles/android-ciclo-de-vida.html new file mode 100644 index 0000000000..8252a87639 --- /dev/null +++ b/wiki/articles/android-ciclo-de-vida.html @@ -0,0 +1,315 @@ + + + + + + + + + + + Ciclo de vida de una actividad en Android + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Ciclo de vida de una actividad en Android +

    +
    + + + + + +
    +

    Si hablamos del ciclo de vida de las activities de una aplicación Android, tenemos dos diagramas que lo explican muy bien:

    + +

    Ciclo de vida de una actividad Android

    + +

    Fuente

    + +
    + +

    Ciclo de vida secuencial

    + +

    Fuente

    + +

    Esto es importante tenerlo en cuenta para manejar la navegación entre las actividades, en especial cuando éstas comparten datos entre sí y se van solapando. Cuando hay actividades que consumen una gran cantidad de recursos, la VM guarda el estado de las actividades que están en segundo plano y las saca del stack de aplicaciones en memoria para luego volverlas a la vida cuando sea necesario. Esto implica definir cuál es ese estado que debe recuperarse o actualizarse cuando la actividad esté nuevamente disponible.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/android-instalacion.html b/wiki/articles/android-instalacion.html new file mode 100644 index 0000000000..c85d7f6ef0 --- /dev/null +++ b/wiki/articles/android-instalacion.html @@ -0,0 +1,460 @@ + + + + + + + + + + + Preparacion de un entorno de desarrollo android + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Preparacion de un entorno de desarrollo android +

    +
    + + + + + +
    +

    + +

    + +

    Download e instalación base

    + +

    La instalación que nosotros recomendamos es la siguiente:

    + +
      +
    • Android Studio +
        +
      • Al descargarlo para tu sistema operativo, se abre un asistente
      • +
      • En la presentación, dar Next (Siguiente)
      • +
      • Elegir el tipo de instalación Standard (por defecto) y presionar Next (Siguiente)
      • +
      • Se visualizan las opciones elegidas, presionamos Next (Siguiente)
      • +
      • y un último Finish hace las descargas necesarias (esperar pacientemente)
      • +
      +
    • +
    • Android SDK +
        +
      • Si vas a trabajar con tu celular como dispositivo de pruebas descargate entonces sa misma versión del SDK (ver más abajo en Configuraciones)
      • +
      • Si vas a trabajar con un emulador, descargate la última versión
      • +
      • Seguir los pasos que se explican en la URL de descarga (se adapta al sistema operativo e idioma de la máquina)
      • +
      +
    • +
    + + + +

    Importante: Configuraciones

    + +

    Las configuraciones que te recomendamos son:

    + +
      +
    • Si estás familiarizado con los shortcuts del Eclipse: File > Settings > Keymap y en el combo Keymaps seleccionar Eclipse
    • +
    + + + +
      +
    • +

      Para hacer las pruebas tienen dos opciones: utilizar un dispositivo Android conectado a USB (algo que recomendamos si tenés una máquina con menos de 4GB de memoria) o bien configurar un emulador mediante el Android Virtual Device (AVD). El AVD Manager aparece desde el menú Tools > Android > AVD Manager.

      +
    • +
    • AVD Name: El nombre que quieran
    • +
    • Device: Nexus 5 4.95” 1080x1920 420dpi
    • +
    • Nougat: Android 7.0 x86_64
    • +
    • Scale: Auto
    • +
    • Emulated Performance: Use Host GPU chequeado, Store a snapshot for faster startup deschequeado
    • +
    + +

    Igualmente pueden configurar cualquier otro dispositivo (Phone o Tablet recomendado, no Wear porque tiene características muy diferentes)

    + +
    +

    IMPORTANTE: Si usás tu celular como dispositivo de pruebas, tienen que coincidir la versión de tu celular con la que vas a configurar en el proyecto.

    +
    + + + +

    Cómo bajarse los ejemplos

    + +
      +
    • Para bajarte los ejemplos o bien usás la opción “Check out project from Version Control” y escribís la dirección de los ejemplos, o bien descargás el repositorio Git como un zip y lo descomprimís aparte, para luego hacer Import Project.
    • +
    + + + +
      +
    • Luego reapuntar el SDK al directorio donde se instaló: Tools > Android > SDK Manager: ubican ese directorio Android SDK Location (el que estuvo en el paso $Android_SDK_Path). Además deben tener instalada alguna API (API Level xx, Revision x, Status: deben marcarla y luego seleccionar Apply). Una vez instalado reiniciar.
    • +
    + + + +

    Troubleshooting

    + +

    “could not find SDK folder”

    + +

    Implica que no están apuntando al SDK que instalaron o bien que no instalaron el Android SDK. Solución: Tools > Android > SDK Manager, filtran por Android y marcan el SDK Location que corresponda.

    + +

    No se puede ejecutar una app: “no devices”

    + +

    Si al correr ven un mensaje de error que indica que no tienen devices, deben configurar un dispositivo para correr la aplicación Android (Android Virtual Device Manager del menú Window) o bien utilizar un dispositivo real conectado a USB.

    + +

    “NO System images installed for this target”

    + +

    Si aparece ese error cuando quieren configurar un device y no les habilita el botón Ok, esto implica que falta descargar del Android SDK Manager las VM (imágenes) de los dispositivos que quieren emular. Vayan entonces al Android SDK Manager y fíjense qué packages hay disponibles para instalar según la versión de Android que están ejecutando.

    + +

    You can’t combine swipe dismissal with ActionBar #1

    + +

    Si al correr la aplicación aparece en el LogCat ese siguiente mensaje revisar si el device es Android Wear, porque no es compatible con los ejemplos.

    + + + +

    Cómo empezar

    + + + + + +

    Herramientas de desarrollo

    + + + + + +

    Links relacionados

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/android-introduccion.html b/wiki/articles/android-introduccion.html new file mode 100644 index 0000000000..a6891bccd1 --- /dev/null +++ b/wiki/articles/android-introduccion.html @@ -0,0 +1,450 @@ + + + + + + + + + + + Introducción al desarrollo con Android + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Introducción al desarrollo con Android +

    +
    + + + + + +
    +

    Antes de comenzar

    + +

    Si les interesa algo de historia, pueden revisar la página de Wikipedia

    + +

    Qué es Android

    + +

    Android es un conjunto de tecnologías open source que vienen con

    + +
      +
    • un Sistema Operativo (Linux)
    • +
    • una Virtual Machine (VM) hecha en Java que se llama Android Runtime (ART, anteriormente tenía el nombre Dalvik)
    • +
    + +

    sobre la cual corren aplicaciones. Funciona en dispositivos móviles, esto incluye teléfonos celulares, tablets, smart TVs, etc.

    + +

    La arquitectura incluye funciones de bajo, medio y alto nivel:

    + +

    Android Architecture

    + +

    En la figura aparecen los servicios ordenados arriba por los de más alto nivel y yendo hacia los de más bajo nivel (más cercanos al hardware del dispositivo)

    + +

    Desarrollar en Android

    + +

    Para desarrollar en Android, necesitás

    + +
      +
    • una SDK o Kit para desarrollar
    • +
    • un IDE, que puede ser Android Studio (basado en IntelliJ IDEA) o bien el Eclipse con plugins
    • +
    • un entorno (runtime) en el cual instalar y probar tus aplicaciones. Si no estás programando en un dispositivo móvil, hay una diferencia entre la VM en la que desarrollás y la VM en la que efectivamente corre la aplicación (por eso no vas a poder utilizar LocalDate, entre algunas otras cosas). Las opciones son +
        +
      • utilizar un emulador de dispositivos, como el AVD: Android Virtual Device (que promete ser más liviano que sus predecesores) o Genymotion
      • +
      • o bien conectar un dispositivo real con Android a tu máquina y deployar las aplicaciones en ese entorno.
      • +
      +
    • +
    + +

    Android - Development Environment

    + +

    Para más información podés ver esta página.

    + +

    Algunas consecuencias que surgen

    + +
      +
    • es difícil el testeo de una aplicación
    • +
    • aquí más que nunca es importante poder separar los componentes tecnológicos y los del negocio, que son más fáciles de testear en forma unitaria, aislada e independiente
    • +
    • también tenemos que conocer las diferencias entre el emulador y el dispositivo real
    • +
    + +

    Android Compilation Process

    + +

    Tipos de Desarrollo en Android

    + +

    Existen diferentes formas de desarrollar aplicaciones para dispositivos Android:

    + +
      +
    • web adaptado a dispositivos móviles
    • +
    • desarrollos híbridos
    • +
    • desarrollos nativos
    • +
    + +

    Veamos a grandes rasgos de qué se trata cada una.

    + +

    Desarrollo web adaptado a mobile

    + +

    Consiste en adaptar (o crear desde cero) una aplicación web, es decir HTML + CSS, pero teniendo en mente que va a ser utilizada desde un dispositivo móvil. Por ejemplo

    + +
      +
    • la vista puede tener una interfaz táctil
    • +
    • la vista será más pequeña que una computadora de escritorio, +o bien que mientras en el escritorio la relación ancho:alto es 16:9, 4:3,- en el dispositivo móvil la pantalla suele tener por defecto disposición vertical (pantalla más alta que ancha), pero podríamos querer rotar a una disposición apaisada (portrait vs. landscape)
    • +
    + +

    Para esto existen varias bibliotecas javascript específicas como:

    + + + +

    Además de las limitaciones propias de las aplicaciones web -cuya naturaleza es stateless- requiere estar permanentemente conectado a una red móvil para que la aplicación pueda funcionar: no hay ningún tipo de procesamiento local. Esto implica que al relegar toda la carga en el servidor

    + +
      +
    • se está desaprovechando las capacidades del dispositivo
    • +
    • el servidor debe tener capacidad para soportar esa carga
    • +
    + +

    Por otro lado, tiene las ventajas conocidas de las aplicaciones web: administración centralizada en el servidor, utiliza la misma tecnología para hacer una única aplicación. De todas maneras cabe destacar que el esfuerzo de adaptación en la interfaz no es menor y depende mucho del tipo de aplicación.

    + +

    Desarrollo nativo

    + +

    En el desarrollo nativo se trabaja utilizando la misma tecnología que provee el dispositivo en el cual se trabaja, esto incluye no sólo iOS, Windows Phone, Android sino diferentes tipos de dispositivo y versiones de sistema operativo.

    + +

    Mientras que esto acopla la aplicación a la plataforma utilizada, y requiere de un desarrollador especializado en esa tecnología, hay dos grandes ventajas al respecto:

    + +
      +
    • se aprovechan al máximo las capacidades y features de ese dispositivo
    • +
    • es posible trabajar en forma local (offline) por un cierto tiempo y sincronizar la información entre cliente y servidor
    • +
    + +

    Más adelante hablaremos de la forma de distribuir las aplicaciones.

    + +

    Desarrollo híbrido

    + +

    En este tipo de desarrollo se trabaja en parte web y en parte con desarrollo nativo. También suelen incluirse en esta categoría los desarrollos generados con productos que soportan varias plataformas móviles (como SAP Fiori, o Appcelerator que son libres y open source). Estos productos limitan los features a utilizar a favor de tener una única aplicación global para todas las plataformas.

    + +

    Comparación de Desarrollos Android

    + +

    Fuente

    + +

    Comparación entre Arquitecturas

    + +

    Android Nativo vs. Web

    + +

    Este diagrama comparativo muestra pros y contras entre webmobile apps y aplicaciones nativas.

    + +

    Fuente

    + +

    Distribución de aplicaciones nativas

    + +

    Uno de los grandes dolores de cabeza al construir aplicaciones de cliente rico es que tenían un alto costo la instalación y el posterior mantenimiento de versiones. Por ese motivo la mayoría de los vendedores desarrollaron el concepto de tienda donde se centraliza el deploy de las aplicaciones y la posterior instalación en cada uno de los clientes. Así tenemos Apple Store para iOS, Play Store para Android, Windows Store para Windows Phone, BlackBerry World, etc.

    + +

    La publicación de nuestra aplicación en la tienda sigue un circuito de aprobación previo por parte de los proveedores de la plataforma (en algunos casos como Apple ese circuito puede transformarse en algo bastante burocrático, que incluya revisiones de código, el pago o la suscripción como desarrollador a esa plataforma, etc.)

    + +

    La ventaja es que una vez lograda la publicación, la aplicación local del dispositivo se encarga de verificar si la aplicación soporta la versión del aparato, los temas de licenciamiento y la instalación en sí.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/angular-instalacion.html b/wiki/articles/angular-instalacion.html new file mode 100644 index 0000000000..c0668e572b --- /dev/null +++ b/wiki/articles/angular-instalacion.html @@ -0,0 +1,870 @@ + + + + + + + + + + + Instalacion de Entorno Angular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Instalacion de Entorno Angular +

    +
    + + + + + +
    +

    + angular +

    + +

    Entorno

    + +

    Es necesario que instales las siguientes herramientas, en este orden:

    + + + +
    +
    +
    +      npm install -g @angular/cli
    +
    +    
    +
    +
    + +

    Editor de Texto

    + +

    Visual Studio Code

    + + + +

    Los plugins del Visual Studio Code que te recomendamos al 2023 son los que ya instalaste para trabajar con HTML/CSS y los siguientes:

    + +

    Necesarios

    + +
      +
    • Path Intellisense (Christian Kohler): autocompletado para archivos de tu file system
    • +
    • Auto Import (steoates): ayuda y autocompletado para importar componentes de JS
    • +
    • Angular Files (Alexander Ivanichev): agrega un menú contextual para crear elementos de Angular
    • +
    • Angular Snippets (Version 16) (John Papa): los snippets permiten generar código para servicios y componentes en forma rápida
    • +
    • JSON to TS (MariusAlchimavicius): te construye una interfaz de TS en base a la información de un JSON
    • +
    • Angular Language Service (Angular): autocompletado dentro del template html
    • +
    • Material Icon Theme (Philipp Kief)
    • +
    • Git Lens (GitKraken), para ver el historial de Git integrado con tu Visual Studio Code
    • +
    • ESLint (Microsoft): para disparar el linter de la sintaxis de TS
    • +
    + +

    Si tenés instalada la extensión Prettier - Code formatter (Prettier) te recomendamos desinstalarla y reemplazarla por Prettier ESLint (Rebecca Vest): es el plugin que vamos a utilizar para aplicar el formato y ejecutar el proceso linter con la sintaxis de la cursada, que define:

    + +
      +
    • no usar puntos y coma al final de cada sentencia
    • +
    • utilizar comillas simples para strings, un estándar en el mundo Javascript/Typescript
    • +
    • evitar imports innecesarios o definiciones de variables que luego no se usen
    • +
    • etc.
    • +
    + +

    Más abajo te indicamos los dos archivos que definen esta configuración: .eslintrc.json y .prettierrc.json.

    + +

    Opcionales

    + +
      +
    • Import Cost (Wix): permite calcular cuántos KB pesa cada import
    • +
    • Angular2-Switcher (infinity1207): agrega shortcuts para navegar entre .ts, .css, .html
    • +
    • Angular2 Inline (Nate Wallace): syntax highlighting y autocompletado de código para componentes Angular inline (que tienen embebido html y css)
    • +
    • REST Client (Huachao Mao): para hacer pedidos http desde Visual Studio Code directamente (podés usar POSTMAN, Insomnia o Swagger + navegador también)
    • +
    + +

    Alternativa a Visual Studio Code

    + +

    Otra opción es utilizar Web Storm (de la suite de IntelliJ), si tienen una cuenta de la facultad pueden solicitar una licencia educativa. Solo que como no vamos a aprovechar todas las herramientas de este IDE poderoso quizás convenga ir por el Visual Studio Code.

    + +

    Aprendiendo Typescript

    + +

    Typescript es el lenguaje de programación base para Angular. Tranquilo, es muy similar a los lenguajes orientados a objetos en los que ya trabajaste. Para iniciarte o para hacer consultas te dejamos estos links:

    + + + +

    Crear un proyecto Angular desde cero

    + +

    En la consola Git Bash o bien desde una terminal de Linux hacemos

    + +
    +
    +
    +      ng new nombre-de-tu-app
    +cd nombre-de-tu-app
    +ng serve -open  # o bien, la versión corta es ng s -o
    +
    +    
    +
    +
    + +

    Correr los tests de un proyecto

    + +

    Para ejecutar los tests de un proyecto, te posicionás en el directorio raíz y ejecutás desde la consola

    + +
    +
    +
    +      ng test
    +
    +    
    +
    +
    + +

    Archivo de configuración para Visual Studio Code

    + +

    Te recomendamos que dentro del proyecto crees una carpeta .vscode y dentro un archivo settings.json que tenga este contenido:

    + +
    +
    +
    +      {
    +    "[javascript]": {
    +      "editor.defaultFormatter": "rvest.vs-code-prettier-eslint",
    +      "editor.formatOnPaste": false, // required 
    +      "editor.formatOnType": false, // required
    +      "editor.formatOnSave": true, // optional 
    +      "editor.formatOnSaveMode": "file", // required to format on save
    +    },
    +    "[typescript]": {
    +      "editor.defaultFormatter": "rvest.vs-code-prettier-eslint",
    +      "editor.formatOnPaste": false, // required 
    +      "editor.formatOnType": false, // required
    +      "editor.formatOnSave": true, // optional 
    +      "editor.formatOnSaveMode": "file", // required to format on save
    +    },
    +    "[json]": {
    +      "editor.defaultFormatter": "rvest.vs-code-prettier-eslint",
    +      "editor.formatOnPaste": false, // required 
    +      "editor.formatOnType": false, // required
    +      "editor.formatOnSave": true, // optional 
    +      "editor.formatOnSaveMode": "file", // required to format on save
    +    },
    +    "editor.codeActionsOnSave": {
    +      "source.fixAll": true
    +    }
    +}
    +
    +    
    +
    +
    + +

    Cambios al package.json

    + +

    Dentro del archivo package.json del raíz de tu proyecto debés tener estos scripts:

    + +
    +
    +
    +        "scripts": {
    +    "ng": "ng",
    +    "start": "ng serve",
    +    "build": "ng build",
    +    "watch": "ng build --watch --configuration development",
    +    "test": "ng test",
    +    "lint": "eslint \"**/*.{ts,tsx}\" ",
    +    "lint:fix": "eslint --fix \"**/*.{ts,tsx}\" ",
    +    "build:prod": "ng build --prod",
    +    "test:prod": "ng test --browsers=ChromeHeadless --watch=false --code-coverage"
    +  },
    +
    +    
    +
    +
    + +

    Agregando Dependencias

    + +

    Instalaremos algunas dependencias adicionales:

    + +
    +
    +
    +      # Installar ESLint
    +npm install --save-dev eslint @typescript-eslint/parser
    +
    +# Instalar plugins adicionales
    +npm install --save-dev @typescript-eslint/eslint-plugin eslint-plugin-prettier
    +
    +# Instalar Prettier y sus dependencias
    +npm install --save-dev prettier prettier-eslint eslint-config-prettier
    +
    +    
    +
    +
    + +

    Archivo .nvmrc

    + +

    Tener un archivo .nvmrc es conveniente si todo el equipo trabaja con NVM (el versionador de Node). El contenido especifica qué versión de Node vamos a utilizar:

    + +
    +
    +
    +      20.4.0
    +
    +    
    +
    +
    + +

    Ejemplo de .gitignore

    + +

    Te recomendamos que configures tu archivo .gitignore de la siguiente manera:

    + +
    +
    +
    +      # See http://help.github.com/ignore-files/ for more about ignoring files.
    +
    +# compiled output
    +/dist
    +/tmp
    +/out-tsc
    +# Only exists if Bazel was run
    +/bazel-out
    +
    +# dependencies
    +/node_modules
    +
    +# profiling files
    +chrome-profiler-events*.json
    +
    +# IDEs and editors
    +/.idea
    +.project
    +.classpath
    +.c9/
    +*.launch
    +.settings/
    +*.sublime-workspace
    +
    +# IDE - VSCode
    +.vscode/*
    +!.vscode/settings.json
    +!.vscode/tasks.json
    +!.vscode/launch.json
    +!.vscode/extensions.json
    +.history/*
    +
    +# misc
    +/.sass-cache
    +/connect.lock
    +/coverage
    +/libpeerconnection.log
    +npm-debug.log
    +yarn-error.log
    +testem.log
    +/typings
    +
    +# System Files
    +.DS_Store
    +Thumbs.db
    +
    +# Angular cache
    +.angular
    +
    +    
    +
    +
    + +

    Configuración del linter

    + +

    El linter es el proceso que genera advertencias o errores en base a la sintaxis y semántica de nuestros componentes. Lo interesante es que podemos configurar, por ejemplo, que escribir console.log o debugger no es código que queremos que esté en el ambiente productivo, pero sí podríamos admitirlo en desarrollo. También se puede configurar validaciones como el uso de let en lugar de const, variables sin utilizar, etc. Te dejamos la configuración recomendada en el archivo .eslintrc.json que debe estar en el directorio raíz:

    + +
    +
    +
    +      {
    +  "parser": "@typescript-eslint/parser",
    +  "extends": [
    +    "plugin:@typescript-eslint/recommended"
    +  ],
    +  "parserOptions": {
    +    "ecmaVersion": 2021,
    +    "sourceType": "module"
    +  },
    +  "rules": {
    +    "semi": [
    +      2,
    +      "never"
    +    ],
    +    "@typescript-eslint/explicit-function-return-type": "off",
    +    "@typescript-eslint/explicit-module-boundary-types": ["off"],
    +    "@typescript-eslint/no-var-requires": "off"
    +  }
    +}
    +
    +    
    +
    +
    + +

    Para ejecutar el linter desde la línea de comandos, podés escribir

    + +
    +
    +
    +      npm run lint
    +
    +    
    +
    +
    + +

    con el archivo package.json que contenga los scripts que arriba te dejamos. Es importante hacerlo ya que el CI de Github Actions lo va a ejecutar para pasar el build, para arreglar automáticamente todos los problemas que detecta el linter podés hacer

    + +
    +
    +
    +      npm run lint:fix
    +
    +    
    +
    +
    + +

    Configuración del archivo de test

    + +

    Al archivo karma.conf.js que está en el directorio raíz hay que agregarle la opción para que genere el porcentaje de cobertura en formato json también:

    + +
    +
    +
    +          coverageReporter: {
    +      dir: require('path').join(__dirname, './coverage/eg-conversor-angular'),
    +      subdir: '.',
    +      reporters: [
    +        { type: 'html' },
    +        { type: 'text-summary' }, // <-- agregar una coma al final
    +        { type: 'json-summary' }  // <-- agregar esta línea
    +      ]
    +    },
    +
    +    
    +
    +
    + +
    +

    Si no tenés un archivo karma.conf.js lo podés generar desde el Angular CLI: ng generate config karma

    +
    + +

    Otros archivos útiles

    + +

    En la carpeta raíz creá los siguientes archivos

    + +
      +
    • .htmlhintrc (configuración del Linter para HTML), con el siguiente contenido
    • +
    + +
    +
    +
    +      {
    +    "tagname-lowercase": false,
    +    "attr-lowercase": false,
    +    "attr-value-double-quotes": true,
    +    "doctype-first": false,
    +    "tag-pair": true,
    +    "spec-char-escape": true,
    +    "id-unique": true,
    +    "src-not-empty": true,
    +    "attr-no-duplication": true,
    +    "title-require": true
    +}
    +
    +    
    +
    +
    + +
      +
    • .prettierrc.json (configuración de Prettier para eliminar puntos y coma, definir tab de 2 espacios, utilizar single quote, etc.) Es importante que tod@s tengan esta configuración para que no haya un montón de conflictos en git a la hora de pushear.
    • +
    + +
    +
    +
    +      {
    +  "singleQuote": true,
    +  "trailingComma": "none",
    +  "endOfLine": "auto",
    +  "tabWidth": 2,
    +  "semi": false
    +}
    +
    +    
    +
    +
    + +

    Ajustes para el % de cobertura

    + +

    Para tener información más precisa sobre el porcentaje de cobertura de tus tests, en el archivo app.component.spec.ts de tu directorio src/app tenés que agregar este import:

    + +
    +
    +
    +      import './app.module'
    +
    +    
    +
    +
    + +

    Ejemplo de un archivo para Github Actions

    + +

    Para agregar el coverage tenés que reemplazar XXXXXXXXX por el nombre de la carpeta donde está tu proyecto.

    + +

    Te dejamos este archivo de ejemplo que tenés que guardar en .github/workflows/build.yml. Descargalo y reemplazá XXXXXXXXX por el nombre de la carpeta donde está tu proyecto.

    + +

    Cómo configurar los badges en tu README

    + +
      +
    • +

      Para agregar el badge del build de Github Actions, seguí estas instrucciones

      +
    • +
    • +

      Para agregar el badge del porcentaje de cobertura, tenés que agregar la imagen que genera el mismo build de Github Actions (reemplazando XXXXXXX por el nombre de la carpeta donde está tu proyecto):

      +
    • +
    + +
    +
    +
    +      ![Coverage](./badges/XXXXXXX/coverage.svg)
    +
    +    
    +
    +
    + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/aplicacion-parcial.html b/wiki/articles/aplicacion-parcial.html new file mode 100644 index 0000000000..208b9c0716 --- /dev/null +++ b/wiki/articles/aplicacion-parcial.html @@ -0,0 +1,469 @@ + + + + + + + + + + + Aplicacion parcial + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Aplicacion parcial +

    +
    + + + +
    +

    Por aplicación parcial se entiende a la aplicación de una función, pero suministrando menos parámetros que los que esta requiere. El resultado de aplicar parcialmente una función es otra función que espera menos parámetros que la original, ya que puede realizar reemplazos en su definición por expresiones o valores concretos. La aplicación parcial es muy útil para componer funciones y para parametrizar funciones de Orden Superior.

    + +

    Por ejemplo, las siguientes expresiones presentan aplicación parcial:

    + +
      +
    • take 3
    • +
    • (+1)
    • +
    • max "hola"
    • +
    + +

    Para visualizar mejor la transformación que ocurre al aplicar parcialmente una función pueden consultar el tipo de las funciones sin aplicar y parcialmente aplicadas usando :t en el editor de Haskell. Podemos realizar un análisis en función del tipo de las expresiones anteriores, cuantos más parámetros se aplican menor aridad (cantidad de parámetros) tiene la función resultante:

    + +
    *Main> :t take
    +take :: Int -> [a] -> [a]
    +*Main> :t take 3
    +take 3 :: [a] -> [a]
    +
    +*Main> :t (+)
    +(+) :: Num a => a -> a -> a
    +*Main> :t (+1)
    +(+1) :: Num a => a -> a
    +
    +*Main> :t max
    +max :: Ord a => a -> a -> a
    +*Main> :t max "hola"
    +max "hola" :: [Char] -> [Char]
    +
    + +

    En el caso de max “hola” vemos también que no sólo disminuyó la cantidad de parámetros, sino que el tipo de la función resultante es más particular, ya que “hola” obliga a que el otro valor esperado por el max también sea de tipo String para poder compararlos y determinar cuál es mayor en orden alfabético.

    + +

    Las siguientes funciones no están aplicadas parcialmente:

    + +
      +
    • take (no está aplicada)
    • +
    • odd (no está aplicada)
    • +
    • odd 3 (está completamente aplicada, esta expresión no es de tipo función sino que es un booleano)
    • +
    • max 0 3 (está completamente aplicada, esta expresión no es de tipo función sino que es un número)
    • +
    + +

    Una consecuencia de esto es que sólo pueden aplicarse parcialmente funciones de 2 o más argumentos. Para que la aplicación parcial exista, es necesario que las funciones estén currificadas (ver Currificación).

    + +

    Puedo aplicar parcialmente el segundo parámetro en vez del primero?

    + +

    En ocasiones sucede que no podemos aplicar parcialmente una función ya que el valor que le queremos pasar no es el primero que espera sino otro, por ejemplo si quiero saber si un nombre es exótico, que se cumple si tiene x, k, q o w, no sería correcto intentar hacer:

    + +

    esExotico nombre = any (elem "XKQWxkqw") nombre

    + +

    Ya que “xkqw” que es la lista en la cual quiero verificar si se encuentra uno de los caracteres del nombre, no es correcto tratar de aplicárselo a elem porque debería ser el segundo parámetro, no el primero. De hecho esa función va a compilar correctamente, pero no va a funcionar como esperamos, ya que al intentar usarla de esta forma:

    + +

    > esExotico "Xiomara"

    + +

    Nosotros esperaríamos que nos diga True, pero vamos a tener un error de tipos:

    + +

       Couldn't match expected type `[ [Char] ]' with actual type `Char'

    + +

    Esto sucede porque si a elem le aplicamos un String (equivalente a [Char]), el resultado va a ser una función de tipo [ [Char] ] -> Bool

    + +

    Formas posibles de resolverlo:

    + +

    Usando una expresión lambda

    + +

    esExotico nombre = any (\letra -> elem letra "XKQWxkqw") nombre

    + +

    Usando notación infija (como los operadores) en vez de prefija: En ocasiones nos parece más natural usar las funciones de dos argumentos de forma infija, por ejemplo:

    + +

    > 10 `mod` 2

    + +

    Podemos aprovechar ese feature para aplicar el segundo parámetro y no el primero como hacemos con los operadores, por ej. (/2)

    + +

    esExotico nombre = any (`elem` "XKQWxkqw") nombre

    + +

    Usando la función flip

    + +

    En Haskell existe una función de Orden Superior llamada flip cuyo tipo es (a -> b -> c) -> b -> a -> c, y sirve justamente para resolver esta clase de problemas ya que lo que hace es aplicar la función que recibe con los parámetros en el orden inverso al que le llegan. Podríamos usar flip parcialmente aplicada para lograr nuestro objetivo.

    + +

    esExotico nombre = any (flip elem "XKQWxkqw") nombre

    + +

    Ejemplos de aplicación parcial

    +

    Uso

    +

    Suponiendo que se tiene una función genérica como el between, genérica porque tiene bocha de parámetros:

    + +
    between menor mayor nro = menor <= nro && nro <= mayor
    +
    + +

    Y se usa así:

    + +
    > between 5 10 7
    +True
    +
    + +

    Podés hacer nuevas funciones a partir de esa, aplicando parcialmente. +Por ejemplo, podés hacer una función más específica, que tome, en vez de tres cosas, sólo una:

    + +
    (between 18 65)
    +
    + +

    ¡Porque le falta un parámetro!

    + +

    Y se puede usar para componer:

    + +
    debeVotar persona = (between 18 65 . edad) persona
    +
    + +

    Ejemplo

    + +

    Supongamos que trabajamos para Spotify. Recién estamos empezando, y tenemos que modelar las canciones y los usuarios en Haskell. +Elegimos modelarlos con data, donde cada canción tiene un nombre, la cantidad de likes y dislikes; y cada usuario tiene un nombre de usuario y un número que representa hace cuántos años usa Spotify:

    + +
    data Cancion = UnaCancion String Float Float
    +data Usuario = UnUsuario String Float
    +
    + +

    Para decidir si poner una canción en la pantalla de inicio de un usuario, el Sr. Spotify nos comenta que usan un algoritmo muy raro, +con un cálculo llamado tasaDeRecomendabilidad, que depende tanto de la canción como del usuario; y ponen una canción en la pantalla de inicio de alguien si esa tasa da mayor a 1000. El cálculo de la tasaDeRecomendabilidad es una formulita que nos dan ellos, y nos dicen que se calcula así:

    + +
    tasaDeRecomendabilidad (UnUsuario _ antiguedad) (UnaCancion _ likes dislikes) = likes / dislikes * antiguedad + likes * pi / 29
    +
    + +

    Notar que el cálculo es ridículamente extraño (pero nosotros nos abstraemos de él). Y deciden si la tasa pasa su evaluación así:

    + +
    esTasaRecomendable tasa = tasa > 1000
    +
    + +

    Nos delegan escribir cómo decidir si una canción se pone en la pantalla de inicio de un usuario. Entonces hacemos:

    + +
    vaEnPantallaDeInicioDe usuario cancion = (esTasaRecomendable.tasaDeRecomendabilidad usuario) cancion
    +
    + +

    Acá, tasaDeRecomendabilidad es una función de 2 parámetros, pero como ya le pasamos uno, tasaDeRecomendabilidad usuario es una función de 1 parámetro. Porque ahora sólo espera 1 parámetro, no 2 (el primero ya lo tiene).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/aplicacion.html b/wiki/articles/aplicacion.html new file mode 100644 index 0000000000..1c7f56b7eb --- /dev/null +++ b/wiki/articles/aplicacion.html @@ -0,0 +1,416 @@ + + + + + + + + + + + Aplicacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Aplicacion +

    +
    + + + +
    +

    Cuando se aplica una función a unos argumentos, el resultado se obtiene sustituyendo esos argumentos en el cuerpo de la función respetando el nombre que se les dio a cada uno. Es posible que esto produzca un resultado que no puede ser simplificado (e.g. un número); pero es más común que el resultado de esa sustitución sea otra expresión que contenga otra aplicación de funciones, entonces se vuelve a hacer el mismo proceso hasta producir un resultado que no pueda ser simplificado (un resultado final).

    + +

    Por ej., siendo doble:

    + +
    doble x = x + x
    +
    + +

    El resultado de aplicar doble 3 (o sea, la función doble aplicada al número 3) se puede obtener de la siguiente manera:

    + +

    doble 3 += { aplicamos la función doble } +3 + 3 += { aplicamos la función + } +6

    + +

    Si queremos obtener el resultado de doble (doble 2) en donde la función doble es aplicada 2 veces, podemos hacer:

    + +

    doble (doble 2)

    + +

    = { aplicamos la función doble que está dentro del paréntesis}

    + +

    doble (2 + 2)

    + +

    = { aplicamos la función + }

    + +

    doble 4

    + +

    = { aplicamos la función doble }

    + +

    4 + 4

    + +

    = { aplicamos la función + }

    + +

    8

    + +

    También podemos obtener el mismo resultado aplicando primero la función doble de más afuera:

    + +

    doble (doble 2)

    + +

    = { aplicamos la función doble que está afuera del paréntesis }

    + +

    doble 2 + doble 2

    + +

    = { aplicamos la primer función doble }

    + +

    (2 + 2) + doble 2

    + +

    = { aplicamos la primer función + }

    + +

    4 + doble 2

    + +

    = { aplicamos la función doble }

    + +

    4 + (2 + 2)

    + +

    = { aplicamos la segunda función + }

    + +

    4 + 4

    + +

    = { aplicamos la función + }

    + +

    8

    + +

    El orden en que realicemos las reducciones (basta de decirle simplificar) no afecta al resultado final pero sí a la eficiencia. Lo copado es que hay un motor que se encarga de esto (se llama motor de reducciones CUAC!). Para entender un poco más lo que pasa detrás de escenas hace falta meterse en la estrategia de evaluación usada por el motor.

    + +

    Aplicación de funciones en Haskell

    + +

    Notacion matemática

    + +
    f(a, b) + c d
    +
    + +

    En Haskell

    + +
    f a b + c * d
    +
    + +
      +
    • La aplicación se denota solo poniendo espacio entre la función y sus argumentos.
    • +
    • Además, la aplicación de funciones que no son operadores tiene una precedencia mayor que la de los operadores (un operador es una función que recibe 2 parámetros y se usa de forma infija ya sea un chirimbolo o una función con `)
    • +
    + +

    Las siguientes definiciones son equivalentes, podemos ver la precedencia para la aplicación de div de forma infija y prefija:

    + +
    promedio ns = (sum ns) `div` (length ns)
    +promedio' ns = sum ns `div` length ns
    +promedio'' ns = div (sum ns) (length ns)
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/append-como--foldr-f-a-.html b/wiki/articles/append-como--foldr-f-a-.html new file mode 100644 index 0000000000..5471b90854 --- /dev/null +++ b/wiki/articles/append-como--foldr-f-a-.html @@ -0,0 +1,431 @@ + + + + + + + + + + + Append como foldr f a + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Append como foldr f a +

    +
    + + + +
    +

    El desafío

    + +

    Se trata de escribir la función append en Haskell a partir de la función foldr. Hay tres versiones:

    + +
      +
    1. +

      append = … expresion …

      + +

      donde en la expresión dice foldr en algún lado, y realmente se usa. Se puede hacer usando únicamente tres funciones, foldr y dos más.

      +
    2. +
    3. +

      append = foldr f a

      + +

      donde f puede ser una expresión lambda

      +
    4. +
    5. +

      append = foldr f a

      + +

      donde f no puede ser una expresión lambda

      +
    6. +
    + +

    Soluciones

    + +

    by Nicolás Perez Santoro (lo que sigue a continuación es una transcripción del proceso mental en base al cual llegué a las soluciones).

    + +

    Primero

    + +

    append:: [a] -> [a] -> [a] +foldr :: (a -> b -> b) -> b -> [a] -> b

    + +

    Si defino append = foldr f, si tengo la lista [1,2,3] `append` [4,5,6] el foldr f me va a hacer

    + +

    4 `f` (5 `f` (6 `f` [1,2,3]))

    + +

    Pero si pudiera hacer un flip de los argumentos, sería

    + +

    1 `f` (2 `f` (3 `f` [4,5,6]))

    + +

    Entonces la primer versión del append es

    + +

    append = flip (foldr (:))

    + +

    Segundo

    + +

    La segunda versión tiene la forma

    + +

    append = foldr f a

    + +

    Pero miro el tipo de foldr

    + +

    foldr :: (a -> b -> b) -> b -> [a] -> b

    + +

    Okay, y el tipo de foldr f a ?

    + +

    foldr f a :: [a] -> b

    + +

    Pero yo quiero que foldr f a :: [a] -> [a] -> [a], que es el tipo de append. entonces b es ([a]->[a]). Entonces foldr en este caso queda instanciado así

    + +

    foldr :: (a -> ([a] -> [a]) -> ([a] -> [a])) -> ([a] -> [a]) -> [a] -> ([a] -> [a])

    + +

    Es bastante largo eso…. En fin, quiero que foldr, a partir del valor inicial, que va a ser una funcion, y la primer lista me devuelva una función que dada la segunda lista del append, me de la concatenacion de las listas. complicado. Pero pienso, si la lista de la izquierda está vacía, entonces foldr me tiene que devolver la función id. entonces digo

    + +

    append2 = foldr f id

    + +

    Pero que es f? tiene que ser una función que dado un elemento y una funcion que dada una lista devuelve otra lista, devuelva otra funcion que dada una lista devuelva la lista que devolvería la función esta, pero con el elemento al principio.

    + +

    f :: a -> ([a] -> [a]) -> ([a] -> [a]) +f e g = \ l -> e : g l

    + +

    Y esta es la segunda versión. Un tanto complicadito…

    + +

    Tercero

    + +

    La tercer versión claramente tiene que ser como la segunda, pero sin lambda expresions ….!!! Si reduzco un poco, llego a esto

    + +

    f' e = (.) (e:)

    + +

    Donde

    + +

    (.) :: ([a] -> [a]) -> ([a] -> [a]) -> ([a] -> [a]) +(e:) :: ([a] -> [a])

    + +

    pero

    + +

    (:) :: (a -> [a] -> [a]) +f' :: ([a] -> [a]) -> ([a] -> [a])

    + +

    Los tipos me dicen que componga! pero como compongo?

    + +

    (:) :: a -> ([a] -> [a]) +(.) :: ([a] -> [a]) -> ([a] -> [a]) -> ([a] -> [a])

    + +

    entonces

    + +

    (.) . (:)  :: a -> ([a] -> [a]) -> ([a] -> [a])

    + +

    entonces

    + +

    append3 = foldr ((.) . (:)) id

    + +

    MORALEJA:LOS TIPOS SON MIS AMIGOS. Guían todo el razonamiento…

    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/arena-configuracion.html b/wiki/articles/arena-configuracion.html new file mode 100644 index 0000000000..7ac61777ee --- /dev/null +++ b/wiki/articles/arena-configuracion.html @@ -0,0 +1,758 @@ + + + + + + + + + + + Configuracion de arena + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Configuracion de arena +

    +
    + + + + + +
    +

    + +

    + +

    Estructura de un proyecto Arena

    + +

    En general una aplicación arena consta de dos componentes o partes:

    + +
      +
    • el dominio
    • +
    • la vista
    • +
    + +

    Si bien podemos tener todas las clases de ambas partes en un único proyecto, lo más prolijo es plasmar esa separación en dos proyectos. Porque por ejemplo, para el TP podrán reutilizar el dominio entre las diferentes tecnologías.

    + +

    Dependencias de los proyectos

    + +

    Entonces en ese esquema si seguimos con la idea de que el dominio no debe estar acoplado a la tecnología de la vista directamente, nuestro proyecto “dominio” no dependerá del artefacto arena, pero sí de otro artefacto más abstracto que establece contratos de los objetos de negocio: uqbar-domain.

    + +

    Por otro lado, nuestro proyecto que tendrá la vista en arena sí, lógicamente dependerá del artefacto “arena”.

    + +

    La siguiente figura resume esto:

    + +

    + +

    + +

    Nota: si hacemos un único proyecto con dominio + ui arena, podemos sólo depender de “arena” y transitivamente veríamos a “uqbar-domain”.

    + +

    Lo que deben tener tus pom.xml

    + +

    Dependencias para proyectos de UI - Xtend

    + +

    Si vas a definir tus objetos de dominio en un proyecto aparte (cosa que recomendamos) tenés que definir esta dependencia

    + +
    +
    +
    +      <dependency>
    +  <groupId>org.uqbar-project</groupId>
    +  <artifactId>uqbar-domain</artifactId>
    +  <version>3.6.3</version>
    +</dependency>
    +
    +    
    +
    +
    + +

    Crear un proyecto de Arena en Xtend

    + +

    Si estás trabajando Arena-UI desde xtend, esta configuración contiene todas las dependencias que necesitás (JUnit, el compilador Xtend, Arena UI, Uqbar Domain, etc.):

    + +
    +
    +
    +      <project xmlns="http://maven.apache.org/POM/4.0.0"
    +	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    +	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    +
    +	<modelVersion>4.0.0</modelVersion>
    +	<artifactId>****ACA PONES EL NOMBRE DE TU PROYECTO****</artifactId>
    +	<version>1.0-SNAPSHOT</version>
    +	<name>****UNA VEZ MAS EL NOMBRE DE TU PROYECTO****</name>
    +	<description>****DESCRIPCION DE TU PROYECTO****</description>
    +
    +	<parent>
    +		<groupId>org.uqbar-project</groupId>
    +		<artifactId>arena-xtend-parent</artifactId>
    +		<version>3.6.3</version>
    +	</parent>
    +
    +  <!-- Si tenés dependencias con tu proyecto de dominio -->
    +	<dependencies>
    +		<dependency>
    +			<groupId>GRUPO-PROYECTO-DE-DOMINIO</groupId>
    +			<artifactId>NOMBRE-PROYECTO-DE-DOMINIO</artifactId>
    +			<version>VERSION-ACTUAL-PROYECTO-DE-DOMINIO</version>
    +		</dependency>
    +	</dependencies>
    +  <!-- fin de dependencias con proyecto de dominio -->
    +
    +	<repositories>
    +		<repository>
    +			<id>uqbar-wiki.org-releases</id>
    +			<name>uqbar-wiki.org-releases</name>
    +			<url>http://maven.uqbar.org/releases</url>
    +		</repository>
    +		<repository>
    +			<snapshots />
    +			<id>uqbar-wiki.org-snapshots</id>
    +			<name>uqbar-wiki.org-snapshots</name>
    +			<url>http://maven.uqbar.org/snapshots</url>
    +		</repository>
    +	</repositories>
    +
    +	<build>
    +		<plugins>
    +			<plugin>
    +				<groupId>org.eclipse.xtend</groupId>
    +				<artifactId>xtend-maven-plugin</artifactId>
    +				<version>2.19.0.M1</version>
    +			</plugin>
    +			<plugin>
    +				<artifactId>maven-compiler-plugin</artifactId>
    +				<version>3.5.1</version>
    +				<configuration>
    +					<source>1.8</source>
    +					<target>1.8</target>
    +				</configuration>
    +			</plugin>
    +		</plugins>
    +	</build>
    +</project>
    +
    +    
    +
    +
    + +

    Dependencias para proyectos de UI - Java

    + +

    Agregar dos referencias en el pom

    + +
      +
    • al framework Arena (consideramos Arena = Arena-JFace como predeterminado)
    • +
    • al proyecto de dominio (asumimos que vamos a tener dos proyectos separados, uno para el dominio y otro para la ui).
    • +
    + +

    Por ejemplo, las dependencias en nuestro pom podrían quedar así:

    + +
    +
    +
    +      <dependencies>
    +  <dependency>
    +    <groupId>org.uqbar-project</groupId>
    +    <artifactId>arena-jface</artifactId>
    +    <version>3.6.3</version>
    +  </dependency>
    +  <dependency>
    +    <groupId>uqbar-project.org</groupId>
    +    <artifactId>videoclub-domain</artifactId>
    +    <version>1.0.0-SNAPSHOT</version>
    +  </dependency>
    +</dependencies>
    +
    +    
    +
    +
    + +

    Las otras dependencias como JUnit se toman de la definición del parent project, en caso de ser necesario se debe agregar a mano:

    + +
    +
    +
    +      <dependency>
    +  <groupId>junit</groupId>
    +  <artifactId>junit</artifactId>
    +  <version>4.12</version>
    +  <scope>test</scope>
    +</dependency>
    +
    +    
    +
    +
    + +

    Si no querés tocar el pom.xml a mano, podés agregarlo a través del plugin M2clipse: botón derecho sobre el proyecto, Maven > Add Dependency > buscás “arena” y tiene que aparecer “arena-jface”, buscás la versión que querés (o si tenés dudas la última) y aceptás. Entonces el plugin va a descargarlo (si no lo tiene en tu repositorio local). Lo mismo con las demás dependencias que necesites.

    + +

    Configurar launcher

    + +

    En Run > Run Configurations… > Java Application > New launch configuration (buscá el botón de la toolbar que está a la izquierda) y en la solapa Arguments, tenés que indicarle en VM Arguments que use el Launcher propio de Arena:

    + +
    +
    +
    +      -Djava.system.class.loader=org.uqbar.apo.APOClassLoader
    +
    +    
    +
    +
    + +

    de lo contrario te va a aparecer un mensaje de error:

    + +
    +
    +
    +      Exception in thread "main" java.lang.RuntimeException: Esta aplicación no está corriendo con el ClassLoader necesario. Corra  la aplicación con el siguiente parámetro para la VM: -Djava.system.class.loader=org.uqbar.apo.APOClassLoader. El ClassLoader actual es: sun.misc.Launcher$AppClassLoader@6fd3633c
    +   at org.uqbar.arena.Application.validateClassLoader(Application.java:32)
    +   at org.uqbar.arena.Application.`<init>`(Application.java:24)
    +
    +    
    +
    +
    + +

    En muchos ejemplos tenemos un archivo .launch que tiene esta configuración ya cargada.

    + +

    Troubleshooting

    + +

    ¿Qué hacer cuando nos bajamos ejemplos (o desarrollamos uno nuevo) y no nos andan? Chequear esta lista…

    + +

    Maven - versión

    + +

    Revisá que Maven esté correctamente instalado en tu máquina y que tenés el settings.xml correctamente configurado. Cualquier duda fijate en el tutorial de instalación de Maven.

    + +

    También asegurate que la versión de Maven sea 3.0.x o posterior, o vas a tener un mensaje de error similar a éste:

    + +
    +
    +
    +      [INFO] Unable to initialise extensions
    +Component descriptor role: 'com.jcraft.jsch.UIKeyboardInteractive', implementation: 'org.apache.maven.wagon.providers.ssh.jsch.interactive.PrompterUIKeyboardInteractive', role hint: 'default' has a hint, but there are other implementations that don't
    +
    +    
    +
    +
    + +

    Maven - error de dependencias

    + +

    Maven tiene un solo gran inconveniente: si al tratar de descargar una dependencia tenés un problema de conexión, después de una cierta cantidad de reintentos queda el archivo de la dependencia corrupto y tu entorno no va a funcionar. Las palabras que hay que buscar en la solapa Problems es resolution will not be reattempted until the update interval of central has elapsed or updates are forced.

    + +

    La solución es ir a tu carpeta C:\users\tuUsuario\.m2 (o ~/.m2 de Linux/Mac), verificar la carpeta del componente que te dice que no puede bajar, verificar que no hay un archivo .jar y borrar la carpeta padre. Por ejemplo, nos aparece este mensaje:

    + +
    +  CoreException: Could not get the value for parameter compilerId for plugin execution default-testCompile: PluginResolutionException: 
    +Plugin org.apache.maven.plugins:maven-compiler-plugin:3.5.1 or one of its dependencies could not be resolved:
    +Failure to transfer org.codehaus.plexus:plexus-component-annotations:jar:1.5.5 from https://repo.maven.apache.org/maven2 was cached in the local repository, 
    +resolution will not be reattempted until the update interval of central has elapsed or updates are forced.
    +
    +Original error: Could not transfer artifact org.codehaus.plexus:plexus-component-annotations:jar:1.5.5 from/to central (https://repo.maven.apache.org/maven2): The operation was cancelled.    
    +    pom.xml    /2    line 46    Maven Project Build Lifecycle Mapping Problem
    +
    +
    + +

    Eso está en la carpeta

    + +
    +
    +
    +      C:\users\tuUsuario\.m2\
    +    org\
    +       codehaus\
    +           plexus\
    +              plexus-component-annotations
    +
    +    
    +
    +
    + +

    Y adentro seguro que falta un jar, debe haber un archivo con extension .lastUpdated que indica el momento en el que intentó bajarse la dependencia y falló. Lo mismo hay que hacer con cada uno de los componentes que marque el error.

    + +

    Borrar todos los hijos de .m2 es lo más fácil, pero también les va a llevar infinito tiempo y si la conexión de Internet es mala, les puede volver a pasar el mismo error con distintos componentes.

    + +
    +

    Moraleja: cuando uno se baja dependencias (con Maven o cualquier otra herramienta), hay que asegurarse de tener buena conexión de Internet.

    +
    + +

    Source folders del proyecto

    + +

    Los source folders de los proyectos (que tienen maven como estructura central del proyecto) deben ser +src/main/java y src/test/java (para proyectos Xtend o Java)

    + +

    Si te aparece como source folder sólo el src, o bien si no tenés source folders:

    + +
      +
    1. +

      corré el plugin de maven: botón derecho sobre el proyecto > Configure > Maven project (o mvn compile)

      +
    2. +
    3. +

      si el proyecto tiene la naturaleza Maven (aparece una M sobre el nodo del proyecto en el Project Explorer), probá hacer un Maven > Update project

      +
    4. +
    5. +

      revisá si efectivamente tenés una estructura de directorio src/main/lenguaje, en base al lenguaje que estás utilizando. Esa estructura debe respetarse.

      +
    6. +
    + +

    JDK

    + +

    Revisá que tengas instalada una JDK (no JRE, tiene que ser JDK con las herramientas para desarrollar en Java como el compilador, debug, etc.) y que la versión de ese JDK sea 1.8 ó superior. Si querés usar una JDK 1.7 ó inferior te va a aparecer el siguiente mensaje de error

    + +
    +
    +
    +      java.lang.UnsupportedClassVersionError: ---aplicación de Arena--- : Unsupported major.minor version 51.0
    +
    +    
    +
    +
    + +

    porque Arena está compilado con una JDK 1.8

    + +

    Problemas para encontrar la ventana ejecutable

    + +

    Si te aparece un error similar a éste al correr un “launcher”:

    + +
    +
    +
    +      Error: no se ha encontrado o cargado la clase principal org.uqbar.arena.examples.conversor.xtend.ConversorWindow
    +
    +    
    +
    +
    + +

    Revisá

    + +
      +
    • si tenés correctamente definidos los source folders (punto anterior): al abrir los archivos tiene que aparecer correctamente coloreado y sin errores de compilación
    • +
    • y si tenés apuntado en tu proyecto un JDK válido (que apunte a un directorio que exista en tu PC, revisá Window > Preferences > Installed JREs)
    • +
    + +

    APOClassLoader not found

    + +

    Otro problema que puede aparecer es:

    + +
    +
    +
    +      Error occurred during initialization of VM
    +java.lang.Error: java.lang.ClassNotFoundException: ....APOClassLoader
    +
    +    
    +
    +
    + +

    entonces el problema puede darse porque no te descargó las dependencias de Maven correctamente. Revisá los directorios de tu usuario/.m2/repository porque seguramente te falte bajar dependencias, podés probar haciendo Maven > Update project (forzando el check Update snapshots), es poco probable que eso lo solucione pero al menos te puede ayudar a encontrar el origen de la dependencia errónea.

    + +

    Errores de launchers

    + +

    Otro problema que te puede ocurrir cuando corras un launcher que te descargaste de nuestros ejemplos es que te aparezca un error de este tipo:

    + +
    +
    +
    +      Launch configuration references non-existing project celulares-ui-arena-scala
    +
    +    
    +
    +
    + +

    En este caso el problema es que te descargaste el proyecto del repositorio utilizando otro nombre que el que originalmente definimos. Entonces fijate cuál es el nombre del proyecto que está esperando y renombralo a ese, o bien entrá por el menú Run Configuration y apuntá el launcher al proyecto que vos definiste. Otra opción puede ser que no hayas ejecutado el comando mvn compile (Run As > Maven build… Goal compile)

    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/arena-instalacion.html b/wiki/articles/arena-instalacion.html new file mode 100644 index 0000000000..0c54283281 --- /dev/null +++ b/wiki/articles/arena-instalacion.html @@ -0,0 +1,348 @@ + + + + + + + + + + + Instalacion de arena + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Instalacion de arena +

    +
    + + + + + +
    +

    + +

    Para instalar el entorno de Arena en Xtend

    + +
      +
    • Necesitás una JDK (Java Development Kit) 1.8, no puede ser superior ya que no se lleva bien con el Class Loader de Arena.
    • +
    • Recomendamos usar la última versión de Eclipse (2019-06) para Java (puede ser la versión anterior pero siempre es mejor trabajar con la última) +
        +
      • con el plugin Xtend 2.18 (el Update Site es http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/)
      • +
      +
    • +
    + +

    image

    + +
      +
    • Y la última versión de Maven (no es tan importante que sea la última pero sí que sea 1.3.x)
    • +
    • Si estás trabajando en Windows, descargate el Git Bash
    • +
    • El archivo .travis.yml te lo podés bajar de cualquiera de nuestros ejemplos, o generalo desde cero con este contenido
    • +
    + +
    dist: trusty
    +
    +language: java
    +jdk:
    +  - oraclejdk8
    +
    + + + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/aritmetica-en-prolog.html b/wiki/articles/aritmetica-en-prolog.html new file mode 100644 index 0000000000..0fd76eb395 --- /dev/null +++ b/wiki/articles/aritmetica-en-prolog.html @@ -0,0 +1,480 @@ + + + + + + + + + + + Aritmetica en prolog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Aritmetica en prolog +

    +
    + + + +
    +

    El predicado “is”

    + +

    En Prolog no pasa como en Haskell que tengo funciones que me devuelven cosas, sino que tengo predicados que relacionan individuos ¿Entonces qué sucede cuando quiero hacer cuentas? Si probamos esto en el intérprete de Prolog, que está pensado para evaluar predicados, vamos a ver que falla:

    + +
    ?- 2+2.
    +ERROR: Undefined procedure: (+)/2 (DWIM could not correct goal)
    +
    + +

    Eso no es porque no sea posible sumar números, sino que el + no es un predicado. De hecho, si probamos esto otro, sí funciona:

    + +
    ?- 2+2 > 1.
    +Yes
    +
    + +

    Eso demuestra que la suma anda, y que el predicado (>)/2 se encargó de reducir esa expresión y compararla con el 1, lo cual dio un resultado booleano como hubiéramos esperado.

    + +

    ¿Y como me puedo saber cuál es el resultado de una cuenta? ¿O si una cuenta da un determinado resultado?

    + +

    Bueno, para esos casos, existe el predicado is, que es un predicado de aridad 2 que se puede escribir de forma infija. Al ser un predicado, sabemos que podemos hacer consultas individuales como la siguiente, para saber si es cierto que se verifica que una cuenta da un determinado resultado:

    + +
    ?- 5 is 2 + 3.
    +Yes
    +
    + +

    Pero ojo, la cuenta sólo puede ir a la derecha:

    + +
    ?- 4 + 1 is 2 + 3.
    +No.
    +
    + +

    A la derecha del is se escribe una operación aritmética. A la izquierda del is se escribe el resultado de esa operación aritmética.

    + +

    Luego podemos ver qué tan inversible es para determinar qué otros usos se le puede dar. El is sólo es inversible por el primer parámetro

    + +

    Esto funciona:

    + +
    ?- X is 6 / 2.
    +X = 3
    +
    + +

    Pero esto no:

    + +
    ?- 3 is X / 2.
    +ERROR: is/2: Arguments are not sufficiently instantiated
    +
    + +

    Errores comunes con el is

    + +

    Acá vienen una serie de warnings que deben tener MUY en cuenta:

    + +

    Error: usar = en vez de is

    + +

    Usar = para resolver operaciones aritméticas no es correcto. ¿Por qué no se puede usar = para aritmética? Veamos un ejemplo:

    + +
    ?- 3+5 = 2+6.
    +No
    +?- 3+5 = 5+3.
    +No
    +?- 3+5 = 8.
    +No
    +
    + +

    El muy simpático sólo nos va a decir true cuando las dos expresiones de ambos lados del igual sean idénticas, no va a intentar resolver la igualdad:

    + +
    ?- 3+5 = 3+5.
    +Yes
    +
    + +

    Muy… “útil”, ¿no? :P

    + +

    En general en la materia no vamos a usar el = ya que preferimos el uso de pattern matching y consultas individuales cuando eso nos sirva para resolver el problema que tenemos.

    + +

    Error: tratar de acumular

    + +

    Como ya saben, en lógico no hay asignación sino unificación; una vez que las variables se ligan, permanecen ligadas hasta que termine la consulta, por ende no hay que pensar al is como un mecanismo para asignar. Es decir, no vale preguntar algo como:

    + +
    ?- edad(pepe,E), E is E + 1.
    +No
    +
    + +

    No existe ningún número E que sea igual a E + 1. Supongamos que la edad de pepe era 15, el motivo por el cual es falso es porque 15 no es 16. Básicamente lo que estaría pasando es esto:

    + +
    ?- 15 is 15 + 1.
    +No
    +
    + +

    Error: Usar is para verificar igualdad de valores

    + +

    El is es sólo para operaciones aritméticas. Si bien funciona, lo siguiente es un error conceptual:

    + +
    edad(juan,Edad) :- 
    +  Edad is 10.
    +
    +

    La manera correcta de hacerlo es aprovechando que al hacer pattern matching, prolog verifica que el valor sea ese, sin usar el igual ó el is:

    + +
    edad(juan,10).
    +
    + +

    ¡Y listo!

    + +

    Ver Sobre el uso del igual en Prolog para más información.

    + +

    Error: Usar is para igualar variables

    + +

    Esto es el mismo caso que el error anterior. El is es sólo para operaciones aritméticas. Si bien funciona, lo siguiente es un error conceptual:

    + +
    mismaEdad(PersonaA,PersonaB):-
    +  edad(PersonaA,EdadA),
    +  edad(PersonaB,EdadB),
    +  EdadA is EdadB
    +
    + +

    Lo mismo sucede aquí:

    + +
    mismaEdad(PersonaA,PersonaB):-
    +  edad(PersonaA,EdadA),
    +  edad(PersonaB,EdadB),
    +  EdadA = EdadB
    +
    + +

    La manera correcta de hacerlo es:

    + +
    mismaEdad(PersonaA,PersonaB):-
    +  edad(PersonaA,Edad),
    +  edad(PersonaB,Edad).
    +
    + +

    Porque si dos individuos deben ser el mismo, entonces alcanza con escribirlos con la misma variable, no como otra condición. De esta forma estamos haciendo una consulta existencial respecto a la edad de la PersonaA y luego una consulta individual para validar si es cierto que la edad de PersonaB es esa que ya conocemos. Vemos que de ésta manera mejoramos la declaratividad (leo qué es lo que quiero, y hay menos detalles algorítmicos: si la edad es la misma lo escribo igual y listo). El motor de Prolog se encarga del resto.

    + +

    Ver Sobre el uso del igual en Prolog para más información.

    + +

    Error: Usar is para resolver ecuaciones

    + +

    Como dijimos arriba, el predicado is/2 no es completamente inversible, es inversible solo para el primer argumento, lo que va a la izquierda. O sea, no vale preguntar:

    + +
    ?- 3 is X + 1.
    +ERROR: is/2: Arguments are not sufficiently instantiated
    +
    + +

    Porque el motor de Prolog no sabe resolver ecuaciones. En éste caso, el error dirá algo como “Arguments are not sufficiently instantiated”, lo cual es otra manera de decir “No soy inversible a derecha, sólo me podés poner algo sin unificar a izquierda”

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/arquitecturas.html b/wiki/articles/arquitecturas.html new file mode 100644 index 0000000000..8322f5d15f --- /dev/null +++ b/wiki/articles/arquitecturas.html @@ -0,0 +1,357 @@ + + + + + + + + + + + Arquitecturas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Arquitecturas +

    +
    + + + +
    +

    Un artículo interesante de fowler: http://martinfowler.com/bliki/DatabaseThaw.html

    + +

    Clasificación general de las partes de una aplicación

    + +

    Normalmente uno habla de tres capas, pero hay distintas formas de dividir y las divisiones principales son 4 que las gente agrupa de una u otra manera según distintas escuelas:

    + +

    Presentación +Persistencia +Dominio +Aplicación

    + +

    Transformación de los datos de entrada para hacerlos llegar hasta el dominio

    + +

    Que la presentación no conozca al dominio +Que el dominio no conozca a la presentación

    + +

    Hay un lugar intermedio de almacenamiento:

    + +

    Wrapper del request +Volcar los datos del request en un mapa +Volcar los datos en un dto (bean)

    + +

    Estructura oficial de una aplicación

    + +
      +
    • El struts llena un bean o mapa.
    • +
    • El controller (action de struts) recibe ese bean, invoca a un servicio.
    • +
    • El servicio es la fachada de la aplicación (facade) y esconde y proteje a los objetos de negocio
    • +
    + +

     * Permite tener muchas interfaces de usuario sobre el mismo dominio + * Permite interponer comportamiento genérico como manejo de transacciones y seguridad y remoticidad. + * Maneja la persistencia + * Provee una interfaz simplificada de la aplicación + * Decide qué "casos de uso" publicar y qué cosas no

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/arrays-literales-en-smalltalk.html b/wiki/articles/arrays-literales-en-smalltalk.html new file mode 100644 index 0000000000..ee869a2ca1 --- /dev/null +++ b/wiki/articles/arrays-literales-en-smalltalk.html @@ -0,0 +1,335 @@ + + + + + + + + + + + Arrays literales en smalltalk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Arrays literales en smalltalk +

    +
    + + + +
    +

    Por si les sirve les comento un toque como funciona el tema de los arrays en smalltalk.

    + +

    Acuérdense que en Smalltalk vale usar arrays literales.

    + +

    Array: colección de tamaño fijo.

    + +

    Literal: objetos especiales como números, caracteres, strings, nil, booleanos, arrays literales (cuac), etc.

    + +

    Para usar un Array literal los elementos del array deben ser literales, ejemplos:

    + +

      #('brujula' 'mapa' 'botellaDeGrogXD')

    + +

    Escribir eso, genera un array que tiene 3 strings, si necesitan un Bag pueden escribir

    + +

      #('brujula' 'mapa' 'botellaDeGrogXD') asBag

    + +

    El tema está cuando queremos un array que tiene objetos que deben obtenerse a través de mensajes, ejemplo:

    + +

      #(4+3)

    + +

    Uno ingenuamente se pensaría que eso da un array de un elemento (el objeto 7), pero Smalltalk piensa que quisimos hacer un array que tiene 3 elementos (el 4, el símbolo +, y el 3)

    + +

    Para crear arrays con objetos que no son literales, se deben utilizar arrays dinámicos (en vez de escribir #() se escribe { }, en vez de separarse los elementos con espacio se separan con punto)

    + +

      {4 + 3} "Esto es un array con un solo elemento, el número 7"

    + +

      {4 + 3 . 'hola' size . Date today year} "Esto es un array con tres elementos: 7, 4 y 2011"

    + +

    De todas formas, en los parciales no suele ser habitual el uso de Arrays (ya que queremos colecciones con tamaño variable y los elementos que componen dicha colección son desconocidos al escribir el código).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ast-abstract-syntax-tree.html b/wiki/articles/ast-abstract-syntax-tree.html new file mode 100644 index 0000000000..12f1af548a --- /dev/null +++ b/wiki/articles/ast-abstract-syntax-tree.html @@ -0,0 +1,315 @@ + + + + + + + + + + + Ast abstract syntax tree + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Ast abstract syntax tree +

    +
    + + + +
    +

    —A esto hay que darle forma — AST simplemente es un arbol que lo que hace es representar un programa (o parte de él), se organiza en nodos y puede haber nodos que contengan otros (nada loco).

    + +

    Lo interesante es usarlo, para armarlo ya está hecho, esta bueno aprender a usarlo… Aka… como obtenerlo, como visitarlo, que sabe hacer cada nodo, como agregarle comportamiento.

    + +

    Si abris Pharo vas a ver que los nodos son RBNode, ejemplo RBVariableNode, RBSequenceNode, RBMessageSendNode (...).

    + +

    Si queres ver como armas un AST de un cacho de codigo tenes RBParser parse: unString y te devuelve un nodo del ast (el parente, un program node si parseo bien).

    + +

    No encontre mucho que leer.. a ver vi una presentacion y lei algo a media que me paso ducasse, y despues para ver como se puede jugar con poder sobre el AST lei el paper de Helvetia y otro de SmallLint (este ultimo es bien concreto sobre reglas y transformaciones).

    + +

    Despues me puse a jugar y a reconocer nodos segun lo que esta seleccionado… facil porque abri el AltBrowser que ya lo hacia.

    + +

    Despues nada… browsear el codigo para entender un poco como se implementa… si encontras algo mas organizado decime… (en otro mail te reenvio lo que me mando ducasse para leer)

    + +

    Reng10aEmbeddingLanguages.pdf

    + +

    Reng10bDomainSpecificProgramChecking.pdf

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/atributos-de-calidad.html b/wiki/articles/atributos-de-calidad.html new file mode 100644 index 0000000000..f424a83d91 --- /dev/null +++ b/wiki/articles/atributos-de-calidad.html @@ -0,0 +1,389 @@ + + + + + + + + + + + Atributos de calidad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Atributos de calidad +

    +
    + + + +
    +

    Atributos de calidad (también cualidades del software) son características no funcionales que se consideran deseables en un sistema de software. Sin embargo, no todos los sistemas de software deben tener en cuenta todos estos atributos o cualidades, algunas serán más importantes que otras dependiendo del sistema, y ciertamente no se pueden maximizar todas a la vez.

    + +

    Se establece una diferencia entre cualidades y requerimientos, porque algunas de ellas pueden incorporarse como entrada al diseño por un camino distinto al del análisis (por ejemplo, como restricciones de arquitectura o influencias del entorno).

    + +

    Simplicidad

    + +

    Simplicidad es la ausencia de complejidad o dificultades. En el desarrollo de software puede resultar de interes diferenciar entre complejidades esenciales y accidentales.

    + +
      +
    • Complejidad esencial: las que son propias o intrínsecas al problema que se desea solucionar. Es natural que un problema complejo tenga soluciones con algún grado de complejidad.
    • +
    • complejidades accidentales: aquellas que surgen por malas decisiones de diseño. Naturalmente, se intentará evitar diseñar soluciones que sean más complejas de lo que el problema requiere.
    • +
    + +

    Determinar si una dificultad en un diseño o programa es esencial o accidental, nos permite atacar las dificultades accidentales, buscando soluciones más simples.

    + +

    Correctitud, consistencia, completitud

    + +

    Correctitud:Ausencia de errores. +Consistencia:Coherencia entre las operaciones que realiza el usuario. +Completitud:Capacidad del sistema para realizar todas las operaciones que usuario podría requerir.

    + +

    Un artículo interesante sobre correctitud consistencia y completitud: Worse is better

    + +

    Robustez

    + +

    Robusto es un sistema que goza de buena salud y que brinda garantías de que va a continuar teniendo buena salud. Algunos síntomas de un sistema robusto son:

    + +
      +
    • la capacidad de ser modificado sin introducir errores (opuesto a error prone)
    • +
    • durabilidad del sistema funcionando correctamente (no aparecen errores aleatorios)
    • +
    + +

    Diferentes usuarios tendrán diferentes visiones de la robustez del sistema.

    + +

    Flexibilidad

    + +

    También llamada modificabilidad, es la capacidad para admitir cambios que pueden ser necesarios tanto por un cambio de requerimientos como por la detección de un error que debe ser corregido. Una variante de flexibilidad es la extensibilidad, es decir, la posibilidad de agregar nuevos requerimientos.

    + +

    Performance

    + +

    La performance es una medida de la eficiencia en el uso de recursos del sistema ejecutándose, por ejemplo:

    + +
      +
    • Uso de procesador
    • +
    • Memoria
    • +
    • Almacenamiento permanente (discos rígidos, etc).
    • +
    • Uso de redes
    • +
    • … o cualquier otro recurso físico.
    • +
    + +

    Escalabilidad

    + +

    Es la capacidad de un sistema para trabajar con diferentes cantidades de trabajo, como cambios en el volumen de datos o flujo de pedidos. Con frecuencia se estudia la escalabilidad de un sistema hacia arriba, es decir, se mide la capacidad del sistema para manejar, por ejemplo, un mayor volumen de datos. La medida de escalabilidad no requiere que el sistema funcione intacto en las nuevas condiciones, en cambio es una medida de la facilidad con la que se lo puede adaptar al nuevo entorno, por ejemplo, si está preparado para que yo agregue un servidor más a un cluster eso se podría considerar escalable.

    + +

    También puede ser de utilidad analizar la flexibilidad hacia abajo, es decir, la posibilidad de un sistema de adaptarse a un entorno más sencillo. En estos casos, se analiza, por ejemplo, la posibilidad de evitar el uso de recursos que encarecen el sistema y podrían no ser indispensables, por ejemplo ejecutar toda la aplicación en un único servidor en lugar de cada capa en uno distinto o bien reemplazar determinados componentes adquiridos por otros de menor costo de licencia.

    + +

    Un error común es confundir escalabilidad con extensibilidad.

    + +

    Seguridad

    + +

    Algunas visiones de la seguridad son:

    + +
      +
    • Comprobar la identidad de las personas que intentan acceder al sistema.
    • +
    • Garantizar que sólo las personas específicamente autorizadas pueden ver determinada porción de la información del sistema
    • +
    • Garantizar que sólo las personas específicamente autorizadas pueden modificar determinada porcióń de la información del sistema o bien realizar determinadas acciones.
    • +
    + +

    Usabilidad

    + +

    La facilidad con la que el sistema o componente se puede utilizar o bien aprender a utilizar.

    + +

    Constructibilidad

    + +

    La constructibilidad es una medida inversa a la complejidad de la construcción del sistema. Las decisiones de diseño pueden afectar severamente la dificultad para construir ese sistema.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/backtracking.html b/wiki/articles/backtracking.html new file mode 100644 index 0000000000..5b27bc25d0 --- /dev/null +++ b/wiki/articles/backtracking.html @@ -0,0 +1,369 @@ + + + + + + + + + + + Backtracking + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Backtracking +

    +
    + + + +
    +

    En un programa desarrollado usando el paradigma lógico, existe un “motor” que actúa como control de secuencia para separar el algoritmo de búsqueda de soluciones del conocimiento de cada programa.

    + +

    Durante la ejecución de un programa va evaluando y combinando las reglas lógicas de la base de conocimiento para lograr los resultados esperados. La implementación del mecanismo de evaluación puede ser diferente en cada lenguaje del paradigma, pero en todos los casos debe garantizar que se agoten todas las combinaciones lógicas posibles para ofrecer el conjunto completo de respuestas alternativas posibles a cada consulta efectuada. El más difundido se denomina backtracking, que utiliza una estrategia de búsqueda de soluciones en estructuras de árboles denominada primero en profundidad.

    + +

    El motor de Prolog usa el mecanismo de backtracking para encontrar soluciones a una consulta. Supongamos que tenemos la siguiente base de conocimientos:

    + +
    hijo(homero,bart).
    +hijo(homero,maggie).
    +hijo(homero,lisa).
    +
    +item(bart,patineta).
    +item(bart,gomera).
    +item(lisa,saxo).
    +
    +copado(patineta).
    +copado(saxo).
    +
    +itemCopadoDeHijo(Persona,Item):- 
    +  hijo(Persona,Hijo),
    +  item(Hijo,Item), copado(Item).
    +
    + +

    Si hacemos la consulta existencial:

    + +
    ?- itemCopadoDeHijo(P,I).`
    +P = homero, I = patineta;
    +P = homero, I = saxo;
    +false.
    +
    + +

    ¿Cómo se llega a esa solución?

    + +

    El motor hace la consulta hijo(Persona,Hijo) que tiene 3 respuestas posibles en base a nuestros hechos. Por cada una de esas soluciones posibles iniciales tendrá diferentes caminos por los cuales avanzar.

    + +

    1)

    + +
      +
    • Si Persona es homero e Hijo es bart: Se consulta item(bart,Item), que tiene dos respuestas posibles. +
        +
      • Si Item es patineta, copado(patineta) se verifica, con lo cual es respuesta para itemCopadoDeHijo/2
      • +
      • Si Item es gomera, copado(patineta) no se verifica, con lo cual no es respuesta para itemCopadoDeHijo/2
      • +
      +
    • +
    + +

    2)

    + +
      +
    • Si Persona es homero e Hijo es maggie: Se consulta item(maggie,Item) que no se verifica, con lo cual no se avanza más por este camino.
    • +
    • Si Persona es homero e Hijo es lisa: Se consulta item(lisa,Item), que tiene una respuesta posible.
    • +
    + +

    3)

    + +
      +
    • Si Item se liga con saxo, copado(saxo) es cierto, con lo cual es respuesta para itemCopadoDeHijo/2.
    • +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/bagna-cauda.html b/wiki/articles/bagna-cauda.html new file mode 100644 index 0000000000..96f6df4c5a --- /dev/null +++ b/wiki/articles/bagna-cauda.html @@ -0,0 +1,367 @@ + + + + + + + + + + + Bagna cauda + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Bagna cauda +

    +
    + + + +
    +

    Salsa

    + +

    Para 25 a 30 personas

    + +
      +
    • 46 cabezas de ajo
    • +
    • 2 frascos grandes de anchoas (no sé bien cuántos gramos serían)
    • +
    • 500cc de aceite de oliva
    • +
    • 1/1.5 aceite girasol
    • +
    • 8 potes de crema de 360cc
    • +
    • un sobre de pimienta de 50 g
    • +
    • un puñadito de sal
    • +
    + +

    Nos faltaron las nueces, podría agregarse 1/4 kg de nueces.

    + +

    Ingredientes

    + +

    Para 22/25 personas, entre ellos varios que andaban con ganas de esquivar las verduras:

    + +
      +
    • 2kg de carne saltada
    • +
    • 2kg de salchicha con piel, también saltada igual que la carne.
    • +
    • 1kg de ravioles saltados/fritos
    • +
    • yo había propuesto 12 baguetines de pan, no sé cuánto hubo al final.
    • +
    • 4 plantas de apio
    • +
    • 6 hinojos
    • +
    • 1 repollo no muy grande
    • +
    • 2 bandejas grandes de repollitos de bruselas (blanqueados 10 minutos en agua hirviendo, después de dudar un poco les cortamos los cabitos)
    • +
    • 2 plantas de brócoli (hervidos)
    • +
    • 25 espárragos, saltados (es importante saltarlos en el momento).
    • +
    • 3 kg de papines (hervidos primero y al horno después).
    • +
    • 4 morrones rojos y 2 verdes
    • +
    • Impíamente no conseguimos cardo.
    • +
    + +

    Discusión

    + +

    Habíamos calculado 25 personas, mirando lo que sobró creo que la salsa hasta 28-30 nos alcanzaba. Los ingredientes estuvieron bien para 25.

    + +

    Algunas cosas que se podrían revisar en una repetición:

    + +
      +
    • Aumentar la relación anchoa/ajo. Le pondría por ahí 30 cabezas de ajo y duplicaría las anchoas.
    • +
    • Me van a putear pero yo estaría tentado de que no sea tan pesada. Para eso se podría reemplazar un poco de crema por leche.
    • +
    • Lo que más sobró fue el repollo, evidentemente era mucho.
    • +
    • Las demás verduras anduvieron bien, sobró un poco de cada cosa.
    • +
    • Carne, salchichas y ravioles se agotaron, pero no tuve sensación de que faltaran.
    • +
    • En la fase previa la gente se abalanzó sobre el pan, pero una vez sobre la mesa ya no le dieron tanta bola. Al final me pareció que era un poco mucho.
    • +
    • De las verduras la que más gente escuché destacar fue el morrón. En segundo lugar pondría los repollitos (aunque quedaron bastantes en la olla). A mí me gustaron mucho los espárragos.
    • +
    • Casi nada de los ingredientes tenía sal, creo que estuvo bien… a lo mejor me quedé con ganas de echarle un toque a los papines.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/bajar-un-proyecto-maven-de-un-repositorio-git.html b/wiki/articles/bajar-un-proyecto-maven-de-un-repositorio-git.html new file mode 100644 index 0000000000..1ea35d95a0 --- /dev/null +++ b/wiki/articles/bajar-un-proyecto-maven-de-un-repositorio-git.html @@ -0,0 +1,465 @@ + + + + + + + + + + + Bajar un proyecto maven de un repositorio git + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Bajar un proyecto maven de un repositorio git +

    +
    + + + +
    +

    Descripción

    + +

    Este artículo asume la presencia de un entorno de trabajo con una JDK. En caso de no contar con un repositorio de esas características conviene leer las instrucciones para la preparación de un entorno de desarrollo Java.

    + +

    También se asume la preexistencia de un proyecto mavenizado y publicado en un repositorio Git, si lo que se desea es crear el proyecto en lugar de descargarlo, aquí están las instrucciones para la creación de un proyecto maven básico y su posterior publicación en el repositorio.

    + +

    El proceso tiene los siguientes pasos, que se detallan a continuación:

    + +

    + Git +

    + +
      +
    • Clonar el proyecto desde el repositorio remoto y alojarlo en nuestro espacio de trabajo local.
    • +
    • Adaptar el proyecto maven para ser utilizado dentro del entorno Eclipse.
    • +
    + +

    Descarga (clone)

    + +

    El checkout se puede hacer

    + +
      +
    • desde el eclipse
    • +
    • desde un cliente git
    • +
    • o por consola
    • +
    + +

    A continuación explicaremos los tres pasos por separado.

    + +

    Por línea de comando

    + +

    Para esto debemos

    + +
      +
    • ubicarnos en el directorio de trabajo
    • +
    • saber la URL del repositorio en el que se publicó el proyecto
    • +
    + + + +
    +
    +
    +      $ cd ~/workspace/materia
    +$ git clone https://github.com/uqbar-project/eg-vehiculos-xtend
    +
    +    
    +
    +
    + +

    En el directorio eg-vehiculos-xtend se bajan los recursos del proyecto, incluyendo un directorio .git donde está la información. De ser necesario debemos cambiar la rama o branch de trabajo, por ejemplo al branch dev:

    + +
    +
    +
    +      $ git checkout dev
    +
    +    
    +
    +
    + + + +

    Descarga desde el Eclipse

    + +

    En caso de hacerlo desde el eclipse, la forma de hacerlo es:

    + +
      +
    • Copiar en el portapapeles la URL del repositorio al que queremos apuntar
    • +
    • Ir a la perspectiva “Git”
    • +
    • En la solapa “Git Repositories” hacer click derecho sobre algún espacio en blanco y ahí elegir la opción “Paste Repository Path or URI”, luego botón “Next”…
    • +
    + +

    + Step 1 Git clone +

    + +

    + Step 2 Git clone +

    + +
      +
    • Elegir una rama o branch para descargar (master por defecto), luego botón Next…
    • +
    + +

    + Step 3 Git clone +

    + +
      +
    • Seleccionar la carpeta del destino
    • +
    + +

    + Step 4 Git clone +

    + +
      +
    • Chequear la opción “Import all Eclipse projects after clone finishes”
    • +
    + +

    Descarga de un proyecto desde un cliente git

    + +

    Eso puede variar dependiendo del cliente, te dejamos algunos links

    + + + + + +

    Adaptar un proyecto maven para ser usado desde el Eclipse

    + +

    Si importaste el proyecto desde la consola o bien el cliente solo descargó el proyecto en un espacio de trabajo local, lo que faltaría hacer es File > Import… > Existing Maven projects…

    + +

    Luego de posicionarse en el directorio donde descargamos el proyecto, en particular donde se encuentra el archivo pom.xml, seleccionamos dicho proyecto y luego presionamos el botón “Finish”.

    + +

    Entonces nuestro proyecto toma la definición del pom.xml y se construye para ser usado en el IDE Eclipse. Vemos que la naturaleza del proyecto es Maven, porque tiene una M arriba del ícono del proyecto:

    + +

    + proyecto maven +

    + +

    ¡Y ya podemos comenzar a trabajar!

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/bibliografia-sobre-programacion-avanzada-orientada-a-objetos.html b/wiki/articles/bibliografia-sobre-programacion-avanzada-orientada-a-objetos.html new file mode 100644 index 0000000000..d04a020591 --- /dev/null +++ b/wiki/articles/bibliografia-sobre-programacion-avanzada-orientada-a-objetos.html @@ -0,0 +1,357 @@ + + + + + + + + + + + Bibliografia sobre programacion avanzada orientada a objetos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Bibliografia sobre programacion avanzada orientada a objetos +

    +
    + + + +
    +

    Herramientas de programación y diseño

    + +
      +
    • Carlos Lombardi y Nicolás Passerini, Introducción a la Orientación a Objetos, disponible en: https://drive.google.com/file/d/1RxqvJzyWSkJEl3_lzCMGWQhGkuXGWh2m/view?usp=sharing.
    • +
    • Erich Gamma, Richard Helm, Ralph Johnson y John M. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley Professional Computing Series, 1994
    • +
    • Andrew Hunt y David Thomas, The Pragmatic Programmer: From Journeyman to Master, Addison-Wesley Professional, 1999.
    • +
    • Alfred Aho, John Hopcroft y Jeffrey Ullman, Data Structures and Algorithms, Addison-Wesley, 1983
    • +
    • Steven John Metsker, William C.Wake, Design Patterns in Java, Software Patterns Series, 2006.
    • +
    • Rebecca Wirfs-Brock, Alan McKean, Object Design: Roles, Responsibilities, and Collaborations, Addison-Wesley, 2002.
    • +
    • Michael C. Feathers, Working Effectively with Legacy Code - Robert C.Martin Series, 2004.
    • +
    • Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, Prentice Hall, 2008
    • +
    + +

    Herramientas metodológicas

    + +
      +
    • Kent Beck, Test Driven Development: By Example, Addison-Wesley, 2002
    • +
    • Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software, Addison-Wesley Professional, 2003.
    • +
    • Kent Beck y Cynthia Andres, Extreme Programming Explained: Embrace Change, 2nd Edition, Addison-Wesley, 2004
    • +
    • Martin Fowler, Kent Beck, John Brant y William Opdyke, Refactoring: Improving the Design of Existing Code, Addison-Wesley, 1999
    • +
    • Joshua Kerievsky, Refactoring to Patterns, Addison-Wesley, 2004
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/binding--polimorfismo-y-sobrecarga.html b/wiki/articles/binding--polimorfismo-y-sobrecarga.html new file mode 100644 index 0000000000..36b07a889a --- /dev/null +++ b/wiki/articles/binding--polimorfismo-y-sobrecarga.html @@ -0,0 +1,464 @@ + + + + + + + + + + + Binding polimorfismo y sobrecarga + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Binding polimorfismo y sobrecarga +

    +
    + + + +
    +

    ¿Qué entendemos por Binding?

    + +

    El binding es la relación que se establece entre la invocación a un procedimiento-función-método y el código que se ejecuta. Otro nombre que le damos es dispatch. Los conceptos de binding, polimorfismo y sobrecarga son aplicables a muchos paradigmas, y tienen diferentes formas de ser entendidos en cada uno de ellos. Por el momento, este artículo se concentra fundamentalmente en el paradigma de objetos.

    + +

    Dynamic method invocation

    + +

    En objetos, cada vez que se envía un mensaje, el método invocado depende del receptor. Por ejemplo, en Smalltalk:

    + +

    figuras := {Cuadrado new. Rectangulo new. Circulo new}. +figuras collect: [:f | f superficie ]

    + +

    Si las clases Cuadrado, Rectangulo y Circulo tienen cada una su propia implementación de , cada vez que se envía el mensaje a la referencia el método invocado será uno distinto. Esta característica es una de las más importantes para el paradigma de objetos, ya que habilita algunas de sus herramientas más interesantes.

    + +

    Tipo estático y tipo dinámico

    + +

    Al extender el concepto de dynamic method invocation a un lenguaje con chequeo estático de tipos, es necesario tener en cuenta la información estática que provee el sistema de tipos. En este tipo de lenguajes, a cada expresión se le asigna un tipo en forma estática. Estos tipos se ejecutan para validar la corrección de los programas antes de su ejecución y eliminar algunos posibles errores.

    + +

    El valor que tome la expresión en tiempo de ejecución puede diferir del valor que es asignado a esa expresión en forma estática. Por ejemplo:

    + +

    public interface Figura { +    public double getSuperficie(); +} +public class Circulo implements Figura { +    @Override +    public double getSuperficie() { ... } +     +    public double getRadio() { ... } +} +Figura f = new Circulo();

    + +

    Estáticamente, la variable tiene el tipo , pero cuando ese programa se ejecute, el valor de será un Circulo. La asignación code|Figura f = new Circulo() es válida siempre que sea un subtipo de . A esta regla se la conoce como subsumption.

    + +

    La presencia de tipado estático nos obliga a analizar nuestro código desde las dos perspectivas. Al evaluar se envía el mensaje al objeto referenciado por la variable y por lo tanto se ejecutará el método de la clase . Sin embargo, en el momento de chequear tipos se controla que el tipo de , que es contenga el mensaje enviado.

    + +

    Si intentamos evaluar se produciría un error de compilación, porque esa expresión no pasa el chequeo de tipos. Por eso, decimos que la regla de subsumption conlleva una pérdida de información de tipos. El objeto referenciado por entiende el mensaje , sin embargo el chequeador de tipos no puede verificar eso y rechaza el programa.

    + +

    Sobrecarga

    + +

    Se dice que un nombre de método está sobrecargado en un contexto cuando es utilizado para representar dos o más métodos o funciones distintos, que se diferencian por su tipo. El tipo de un método incluye tanto a los tipos de los parámetros como al del valor de retorno. Por ejemplo:

    + +
      +
    • En Haskell es posible definir funciones con el mismo nombre y distintos tipos de parámetros o distinto tipo de retorno.
    • +
    • En Java o C# es posible definir dos métodos en la misma clase o jerarquía con distinto número de parámetros o con parámetros de distinto tipo. (La posibilidad de sobrecargar métodos variando el tipo de retorno es menos frecuente en el paradigma de objetos.)
    • +
    + +

    Por ejemplo el método está sobrecargado en la clase .

    + +

    class C { +    void m(Figura f) { println(1); } +    void m(Circulo c) { println(2); } +}

    + +

    Cuando se envía un mensaje que está sobrecargado, el sistema debe decidir cuál es el método que se debe ejecutar. En la mayoría de los lenguajes orientados a objetos, esta decisión se toma en forma estática. (Cuando la decisión es dinámica, en lugar de sobrecarga hablamos de Multimethods. Por ejemplo, en la siguiente porción de código, al evaluar se ejecutará el método que recibe una figura, y no el que recibe un círculo; y por lo tanto imprimirá “1”.

    + +

    Figura f = new Circulo(); +C c = new C(); +c.m(f); // => imprime 1!

    + +

    La interpretación que debemos hacer es que que en realidad el mensaje enviado no se identifica únicamente por su nombre, sino que incluye los tipos de los parámetros. Desde esta perspectiva los dos métodos de la clase tienen distinto nombre, son totalmente independientes uno del otro. Debemos interpretar que el primero se denomina y el segundo . En presencia de este tipo de sobrecarga el método a ejecutar se decidirá en tiempo de ejecución, en función del mensaje enviado, pero el mensaje a enviar se decide en tiempo de compilación, a partir de la información de tipos disponible en este momento. En resumen, el mensaje enviado a no es sino . Dado que ambos métodos tienen identificadores distintos, para invocarlos se envían mensajes distintos y la decisión entre ambos será tomada en tiempo de compilación.

    + +

    Veamos un ejemplo más complejo con sobrecarga y redefinición (adaptado de “Foundations of Object-oriented Languages: Types and Semantics” por Kim Bruce), tenemos el siguiente código en Scala:

    + +

    class C { +   def m(other: C) = { println(1) } +} +class SC extends C{ +   def m(other: SC) = { println(3) } +   override def m(other: C) = { println(2) } +}

    + +

    Si hacemos la siguiente prueba:

    + +

    var c2: C = new SC() +var sc: SC = new SC() +c2.m(sc)

    + +

    El resultado será 2, no 3, ya que el mensaje que se elige estáticamente no es m(SC), sino m(C). Para entender lo que sucede podemos hacer dos pasos bien separados: Pensar primero como compilador y después pensar como máquina virtual (pensar en tiempo de compilación y tiempo de ejecución).

    + +

    Empecemos como compiladores: c2 es una variable del tipo C, y sc es una variable del tipo SC. En c2 se referenciará a una instancia del tipo SC, pero eso como compiladores por ahora no nos importa, porque no estamos ejecutando el código.

    + +

    Luego vamos a esta llamada:

    + +

    Acá es donde empieza la confusión: Uno piensa que porque sc es del tipo SC y c2 es una instancia de SC (si bien la variable es de tipo C) el método que se va a ejecutar es m(SC), pero no es así. ¿Por qué? La respuesta viene de pensar como compilador, no “ejecutar” el código y mirar la el tipo de la variable c2, y deducir de ahí los posibles mensajes que entiende, y de ver bien la firma de esos mensajes.

    + +

    ¿De qué tipo es C2? Del tipo C. ¿Qué mensajes entiende un objeto del tipo C? Vamos a ver la declaración de C:

    + +

    class C { +   def m(other: C) = { println(1) } +}

    + +

    Los objetos del tipo C sólo entienden un mensaje, y ese es m(C). Por lo tanto, siendo que SC es un subtipo de C, la firma del mensaje que va a ser llamado en va a ser m(C):Unit y no m(SC):Unit, dado que el tipo C no tiene definido ningún mensaje con parámetro SC. Esa firma es decidida en compilación y depende sólo de los tipos declarados/inferidos de las variables, y no de las instancias.

    + +

    Ahora sabemos la firma, terminamos de compilar el código. Pasemos al modo ejecución y pensemos como máquinas virtuales ¿Qué método se ejecuta al hacer c2.m(sc)? Para saberlo, no hay que hacer otra cosa que method lookup.

    + +
      +
    1. +

      ¿Cuál es la firma del mensaje c2.m(sc)? La firma es m(C):Unit (por lo que vimos antes en “compilación”.

      +
    2. +
    3. +

      ¿A quién le estoy enviando ese mensaje? Al objeto referenciado por c2, que es una instancia de la clase SC.

      +
    4. +
    5. +

      Para saber qué método ejecutará entonces, comenzamos el method lookup a partir de la clase SC.

      +
    6. +
    + +

    class SC extends C { +  def m(other: SC) = { println(3) } +    +  override def m(other: C) = { println(2) } +}

    + +
      +
    1. ¿Tiene SC algún método definido cuya firma sea m(C):Unit? Sí. Entonces ese es el método que se va a ejecutar, que es el que imprime 2.
    2. +
    + +

    Eso sería básicamente todo. Lo importante de todo esto es entender que ahora los tipos son mucho más importantes para la construcción de mi modelo conceptual. Y la idea es que con ejercicios como estos uno comprueba si entendió o no que los tipos me cambian un poquito la semántica del código y me agregan algo más en lo que tengo que pensar, si bien me previenen algunos errores en compilación.

    + +

    Ejemplos

    + +

    Tres ejemplos del lenguaje Java:

    + +
      +
    • Al mandar un mensaje a dos objetos (polimórficos) distintos, el binding es dinámico.
    • +
    • Si un objeto recibe dos mensajes con el mismo nombre pero distintos tipos de parámetros, el bingind es estático. A esto lo llamamos sobrecarga.
    • +
    • Si invocamos un método de clase, el binding es estático.
    • +
    + +

    Algunas variantes

    + +
      +
    • En C++ o C# si no les pongo virtual a los métodos el binding es estático.
    • +
    • En Eiffel se da dinámicamente, a esta característica la denominamos multimethods.
    • +
    • En Smalltalk el binding de los métodos de clases es también dinámico. (Y esto es uno de los motivos que nos da pie a decir que las clases en Smalltalk son realmente objetos, mientras que en Java no es así.)
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/bloques.html b/wiki/articles/bloques.html new file mode 100644 index 0000000000..3d8d49d863 --- /dev/null +++ b/wiki/articles/bloques.html @@ -0,0 +1,461 @@ + + + + + + + + + + + Bloques + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Bloques +

    +
    + + + +
    +

    ¿Qué es un bloque?

    + +

    Un bloque (también conocido como closure) es un objeto, y por lo tanto podemos hacer con él lo mismo que hacíamos con los demás objetos esto es:

    + +
      +
    • Enviarle mensajes
    • +
    • Pasarlo como parámetro de algún mensaje
    • +
    • Hacer que una variable lo referencie
    • +
    + +

    Un objeto bloque representa un cacho de código que no se ejecutó, ese código solo se ejecutará si alguien le manda un mensaje que le indique hacerlo. Veamos algunos ejemplos en el lenguaje Wollok:

    + +

    Si ejecutamos las siguientes instrucciones:

    + +
    var x = 0
    +{ x = x + 1 }
    +
    + +

    ¿A qué objeto apunta la variable x después de ejecutar esas 2 líneas de código? ¡Claro, al objeto cero (0)! Porque sólo creamos el bloque, pero el código del mismo nunca se evaluó.

    + +

    Para que la variable x apunte al objeto uno (1) tenemos que decirle al bloque que se ejecute.

    + +
    var x = 0
    +{ x = x + 1 }.apply()
    +
    + +

    Ahora sí, después de ejecutar esas 2 líneas de código la variable x va a apuntar al objeto uno (1). Es importante darse cuenta que apply() es un mensaje que le llega al objeto bloque. Este mensaje hace que se ejecute el código que está dentro del bloque y que se retorne el objeto devuelto por la última sentencia del bloque.

    + +

    Conocimiento del contexto

    + +

    Algo que se pone en evidencia en este ejemplo introductorio es que los bloques tienen una noción del contexto en el cual fueron definidos, y por eso es que tienen acceso a las referencias disponibles en dicho contexto. Es por eso que es posible usar la variable x que había sido definida fuera del bloque.

    + +

    Si tuviéramos el siguiente código:

    + +
    object pepita {
    +  var energia = 100
    +  
    +  method volar(metros) {
    +    energia -= 10 - metros
    +  }
    +  
    +  method irYVolverNVeces(metros, veces){
    +    veces.times({n => self.volar(metros * 2) })
    +  }
    +}
    +
    + +

    Y luego evaluamos: pepita.irYVolverNVeces(5, 3)

    + +

    El mensaje times(algoParaHacer) que se le manda al número 3 con el bloque que construímos en ese momento se encargará de mandarle el mensaje apply(valor) al bloque que le pasamos, en este caso, 3 veces. Dado que la referencia metros existía en el contexto en el cual ese bloque fue creado (era un parámetro del método), es válido usar esa referencia dentro de la lógica del bloque y va a apuntar al objeto 5, como es de esperarse.

    + +
    +

    El parámetro que se usa para aplicar el bloque será primero 1, luego 2 y finalmente 3. Esta información es irrelevante para el ejemplo, pero el bloque debe recibir un parámetro para que entienda el mensaje que recibirá cuando se evalúe el método times.

    +
    + +

    Otra pregunta interesante es: ¿quién es self dentro del bloque?

    + +

    Cuando usamos self dentro de un bloque, estamos referenciando al mismo objeto que recibió el mensaje dentro del cual se creó el bloque (o sea, pepita), lo cual es muy convieniente ya que hace que no necesitemos parametrizar a self si necesitamos mandarle mensajes o parametrizarlo a otro mensaje dentro del código del bloque.

    + +

    Finalmente, el resultado de la operación será que la energía de pepita se habrá decrementado en 60.

    + +

    Bloques como funciones

    + +

    También se puede ver a los bloques como objetos que representan una función sin nombre (o sea, una función anónima, como las Expresiones lambda de funcional!).

    + +

    El bloque { 1 } en Wollok es como una función constante que siempre devuelve 1 si le decís que se ejecute. Pero el chiste de las funciones es que reciban parámetros y los bloques también pueden recibir parámetros, por ejemplo la sintaxis de Wollok para un bloque de dos parámetros es { parametro1, parametro2 => cuerpoDelBloque }

    + +

    Ejemplos:

    + +

    Podríamos representar las siguientes funciones…

    + +

    f(x) = 2x

    + +

    g(x,y) = x2 + y2

    + +

    … con bloques de la siguiente forma:

    + +

    var f = {x => 2 * x }

    + +

    var g = {x, y => x ** 2 + y ** 2 }

    + +

    ¿Cómo hacemos para usar bloques que tienen parámetros? Por ejemplo si quisiéramos los equivalentes a evaluar las funciones f(4) y g(4,3)

    + +

    f.apply(4) // Esto devuelve el objeto 8

    + +

    g.apply(4, 3) // Esto devuelve el objeto 25

    + +

    Por lo general el uso que le damos a los bloques es sólo la creación de los mismos para pasar por parámetro a funcionalidad ya existente de propósito general, como son los mensajes de colecciones Mensajes de colecciones, y no tanto la aplicación de los mismos. Sin embargo es interesante saber cómo es que las colecciones son capaces de evaluar lo que les pedimos.

    + +

    Para pensar: ¿Los mensajes que esperan por parámetro un bloque, podrán recibir por parámetro un objeto programado por nosotros? ¿Qué es lo que una colección necesita realmente que le pasemos por parámetro para poder realizar un filtrado?

    + +

    ¿Cómo funciona el #ifTrue: y el #ifFalse: de Smalltalk?

    + +

    En el caso de Smalltalk, el uso de bloques es aún más generalizado, ya que al no existir estructuras de control y tener una sintaxis completamente basada en mensajes a objetos, los bloques se usan por ejemplo para poder saber qué hacer en un condicional cuando la condición se cumple o no se cumple. Esto se logra mediante ditintos mensajes que entienden los booleanos que representan la condición sobre la cual queremos decidir.

    + +

    Si en un workspace escribimos

    + +
    pepita energia > 0 ifTrue: [ pepita come: 30 ]
    +
    + +

    Pensando en términos de objeto y mensaje (mensaje = selector + parámetros), ¿qué está pasando acá?

    + +

    El objeto receptor del mensaje ifTrue: es el objeto que me devuelve pepita energia > 0, ese objeto puede ser true o false.

    + +

    Si el receptor es true queremos que el bloque [ pepita come: 30 ] se ejecute. Si el receptor es false NO queremos que el bloque [ pepita come: 30 ] se ejecute.

    + +

    Entonces el objeto que tiene la responsabilidad de saber si el bloque debe o no ejecutarse es el booleano receptor del mensaje ifTrue:.

    + +

    Siendo false la única instancia de la clase False y true la única instancia de la clase True, la implementación del método ifTrue: en cada una de las clases es

    + +
    True >> ifTrue: unBloque
    +  "self apunta a true entonces queremos que se ejecute el bloque"
    +  ^unBloque value
    +  
    +False >> ifTrue: unBloque
    +  "self apunta a false entonces NO queremos que se ejecute el bloque"
    +  ^nil
    +
    + +

    O sea que las estructuras de control a las que estábamos acostumbrados por el paradigma estructurado, no son más que mensajes polimórficos :smile:. Todo sigue las mismas reglas, objetos y mensajes.

    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/brownies.html b/wiki/articles/brownies.html new file mode 100644 index 0000000000..c3a3813234 --- /dev/null +++ b/wiki/articles/brownies.html @@ -0,0 +1,397 @@ + + + + + + + + + + + Brownies + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Brownies +

    +
    + + + +
    +

    Ingredientes:

    + +
      +
    • Chocolate, 150 gramos
    • +
    • Manteca, 100 gramos
    • +
    • Azúcar, “casi” una taza
    • +
    • Huevos, 2
    • +
    • Harina, 1/2 taza
    • +
    + +

    Pasos:

    + +
      +
    1. Ponga la manteca y el chocolate (cortado en trozos) dentro de una sartencita; derritalos en el horno.
    2. +
    3. Bata los huevos con el azúcar hasta que estén bien cremosos y la superficie llena de globitos.
    4. +
    5. Agrégueles el chocolate derretido y tibio; continúe batiendo hasta que vuelvan a formarse globitos. +
        +
      1. NOTA: El chocolate tiene que estar bien mezclado con la manteca porque sino no queda homogéneo. Esa es la parte mas delicada, que el chocolate no se queme ni se pegue (consejo, poner manteca abajo del chocolate para derretirlo).
      2. +
      +
    6. +
    7. Del mismo modo incorpórele la harina.
    8. +
    9. Vierta en una asaderita enmantecada y enharinada de tamaño tal que la preparación quede de 2.5 cm de alto (mas o menos…).
    10. +
    11. Cocine en horno bien caliente hasta que la superficie parezca “craquele” y la preparación este firme pero húmeda. +
        +
      1. NOTA: Esta es una parte sensible es cuando se cocina, porque si se cocina mucho queda duro. La teoría dice que hay que dejarlo en el horno sin abrirlo como media hora, y debería primero como “inflarse” y después baja y se craquela (ahí ya se lo puede pinchar con un escarbadiente en el medio para ver si está cocinado, y tiene que quedar húmedo).
      2. +
      +
    12. +
    13. Retire del horno y deje enfriar en la asadera.
    14. +
    + +

    Una receta alternativa

    + +

    Muy chocolatosa y muy húmeda

    + +
      +
    • Chocolate cobertura, 450 gramos (ojo, no “cobertura de chocolate”)
    • +
    • Manteca, 170 gramos
    • +
    • Azúcar, 340 gramos (con azúcar común se genera una costra más gruesa, con impalpable se consigue una costra más delicada).
    • +
    • Huevos, 2 (mezclar con el azúcar sin batir, para que no quede esponjoso, es más denso que un bizcochuelo)
    • +
    • Harina, 70 gramos (común 0000, no leudante ni polvo de hornear)
    • +
    • Nueces, 100 gramos
    • +
    • Se le puede poner esencia de vainilla.
    • +
    + +

    También se propone poner papel manteca en la placa. Horno bastante caliente (un poco más que medio), de 20 a 25 minutos.

    + +

    Otra opción más tipo “masita”:

    + +
      +
    • 6 huevos
    • +
    • 300 chocolate
    • +
    • 200 manteca
    • +
    • 170 harina
    • +
    • cacao
    • +
    • nueces, 100 gramos
    • +
    • esencia de vainilla
    • +
    + +

    Otra receta alternativa

    + +

    AKA la del asado familiero (los pasos son similares o iguales al anterior) Ingredientes:

    + +
      +
    • 4 huevos
    • +
    • 1 taza y un toque más de harina (preferentemente 0000, y común)
    • +
    • 2 tazas de azúcar
    • +
    • 150 gr de chocolate (recomiendo águila)
    • +
    • 150 gr de manteca
    • +
    + +

    Pasos: 1 - Derretir manteca y chocolate en el microondas. 2 - Romper los huevos (oh si) en un bowl y mezclarlos muy bien con el azúcar. 3 - Mezclar lo del paso 1. con lo del paso 2. Seguir mezclando. 4 - Agregar harina. Seguir mezclando, dije! 5 - En este paso agregarían nueces, almendras o lo que guste. 6 - Yo le pongo manteca y harina al molde porque da fiaca si se pega, aunque no debería pegotearse demasiado por la cantidad de manteca que lleva. 7 - Al horno! Depende el horno y soy muy inexperta, así que voy tanteando con el cuchillo. En general, cuando tiene la parte de arriba crocante y el cuchillo no sale chorreando, ya está bien.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/build_angular.yml b/wiki/articles/build_angular.yml new file mode 100644 index 0000000000..e8eec06721 --- /dev/null +++ b/wiki/articles/build_angular.yml @@ -0,0 +1,40 @@ +name: Build +on: + push: + pull_request: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x] + + steps: + - uses: actions/checkout@v3 + + - name: Cache node modules + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Node ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + + - name: Run tests & linter + run: | + npm ci + npm run test:prod + npm run lint + - name: Coverage badge + uses: demyanets/angular-coverage-badges-action@v1 + with: + coverage-summary-path: coverage/XXXXXXXXX/coverage-summary.json + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/wiki/articles/build_react.yml b/wiki/articles/build_react.yml new file mode 100644 index 0000000000..5e0b03ad55 --- /dev/null +++ b/wiki/articles/build_react.yml @@ -0,0 +1,31 @@ +name: Build React App + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Use Node.js 20.x + uses: actions/setup-node@v3 + with: + node-version: 20.x + - name: Cache node modules + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + - name: Download dependencies with npm + run: npm install + - run: npm ci + - run: npm run build --if-present + - name: Run the tests and generate coverage report + run: npm test -- --coverage + - name: Adding coverage badge + uses: demyanets/angular-coverage-badges-action@v1 + with: + coverage-summary-path: ./coverage/coverage-summary.json + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/wiki/articles/c--.html b/wiki/articles/c--.html new file mode 100644 index 0000000000..782e0eae19 --- /dev/null +++ b/wiki/articles/c--.html @@ -0,0 +1,329 @@ + + + + + + + + + + + C ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + C ++ +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Sobre el lenguaje

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/c.html b/wiki/articles/c.html new file mode 100644 index 0000000000..219807c290 --- /dev/null +++ b/wiki/articles/c.html @@ -0,0 +1,359 @@ + + + + + + + + + + + C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + C +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Sobre el lenguaje:

    + + + +

    Herramientas basadas en C#:

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/calculo-del-tipo-de-una-funcion-en-haskell.html b/wiki/articles/calculo-del-tipo-de-una-funcion-en-haskell.html new file mode 100644 index 0000000000..9cdd682b85 --- /dev/null +++ b/wiki/articles/calculo-del-tipo-de-una-funcion-en-haskell.html @@ -0,0 +1,604 @@ + + + + + + + + + + + Calculo del tipo de una funcion en haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Calculo del tipo de una funcion en haskell +

    +
    + + + +
    +

    Introduccion

    + +

    Dado que el haskell es un lenguaje con Inferencia de tipos, no es necesario indicar el tipo de las funciones que construimos. A pesar de ello (o tal vez precisamente por ello) los tipos juegan un rol fundamental al programar en un lenguaje funcional (en particular en Haskell).

    + +

    El sistema de tipos de Haskell es muy estricto, bastante más de lo que estamos acostumbrados los que venimos de la programación orientada a objetos. Si bien en algunos casos puede ser molesto porque un tipado tan estricto como el de Haskell complica algunas operaciones sencillas como suele pasar con el cálculo de un promedio, en la amplia mayoría de los casos es bueno porque nos ayuda a detectar errores más tempranamente.

    + +

    Esto obliga al programador a ser más atento con los tipos de cada una de las funciones que programa o que utiliza. Los siguientes aspectos de tipado son importantes a tener en cuenta a la hora de entender de qué tipo son las funciones que definimos:

    + +

    La construcción de funciones a partir de funciones

    +

    El paradigma funcional tiene como uno de sus pilares la posibilidad de construir funciones complejas a partir de combinar funciones más simples (utilizando composición, aplicación parcial, orden superior, etc); para poder utilizar cualquiera de esas herramientas es necesario tener presente el tipo de las funciones que quiero combinar, por ejemplo:

    + +
      +
    • Si quiero componer dos funciones f y g: es necesario que la imagen de f esté incluida en el dominio de g (tal como aprendimos en matemática).
    • +
    • Al aplicar una función de orden superior es necesario que matcheen los tipos de la función esperada con la función recibida.
    • +
    + +

    El polimorfismo paramétrico y las type classes

    +

    Una función que tiene un tipo genérico al ser aplicada puede reducir su tipo, eso también es algo a tener en cuenta.

    + +

    Por ejemplo la función filter puede en principio procesar listas de cualquier tipo; en cambio una vez que yo le aplico el primer parámetro (el criterio de selección) ese tipo se restringe. Si el criterio fuera even, ese filtrado sólo va a servir para listas de valores numéricos, porque even restringe el tipo de los elementos de la lista a el tipo de lo que espera recibir, que es un número.

    + +

    A continuación se describen paso a paso los ejemplos que permiten comprender el mecanismo de inferencia utilizado en el lenguaje Haskell.

    + +

    Ahora sí: ¿cómo inferimos el tipo de una función?

    + +

    Antes de poder evaluar el tipo de una hay que comprender cuáles son los tipos posibles de Haskell, eso está explicado en el artículo sobre Tipos de Haskell, y entender la regla básica de tipado para una aplicación: si x es Bool, entonces not x también es de tipo Bool, porque not :: Bool -> Bool; si x es de cualquier otro tipo not x no tipa.

    + +

    Funciones Simples

    + +

    Al intentar calcular el tipo de una función, lo primero que tenemos que hacer es mirar las funciones que se usan dentro de su definición y asegurarnos de saber de qué tipo son esas funciones. Luego las preguntas importantes son:

    +
      +
    1. ¿Cuántos parámetros recibe? Esto ayuda a ordenarnos, para saber cuántos huecos tenemos que llenar, que es esa cantidad + 1, por el tipo de retorno.
    2. +
    3. ¿De qué tipo son esos parámetros? Esto se deduce en base al uso de los mismos en la definición.
    4. +
    5. ¿De qué tipo es lo que retorna? Esto se deduce en base a lo que retorna la función principal que es la “de más afuera” o menor precedencia.
    6. +
    + +

    Por ejemplo:

    + +
    +
    +
    +      none x y = not x && not y
    +
    +-- Sabemos que:
    +-- not :: Bool -> Bool
    +-- (&&) :: Bool -> Bool -> Bool
    +
    +    
    +
    +
    + +

    Luego, para determinar el tipo de la función none podemos seguir los siguientes pasos:

    + +
      +
    1. Vemos que tiene dos parámetros (x e y), entonces podemos decir que su tipo tiene que tener la forma none :: ?? -> ?? -> ??, luego tendremos que calcular cuáles son esas incógnitas.
    2. +
    3. Analizamos el tipo de los parámetros: +
        +
      • Si x es utilizado como parámetro de la función not, podemos deducir que x no admite valores de cualquier tipo, sólo pueden ser booleanos. Por ende: none :: Bool -> ?? -> ??.
      • +
      • Un razonamiento análogo nos lleva a deducir que y también debe ser un valor booleano. Luego: none :: Bool -> Bool -> ??.
      • +
      +
    4. +
    5. Finalmente, para saber el tipo de retorno: +
        +
      • Dado que x es Bool, entonces not x también es de tipo Bool, al igual que not y, lo cual es compatible con lo que espera el (&&) (o sea que la expresión not x && not y tipa).
      • +
      • Lo que retorna la función (&&) al estar totalmente aplicada es Bool, y esa es la función principal, así que podemos afirmar que: none :: Bool -> Bool -> Bool.
      • +
      +
    6. +
    + +

    En el último paso podemos ver que en realidad para saber el tipo de no sería necesario mirar los parámetros de (&&), con saber su tipo de retorno sería suficiente. Sin embargo el análisis es útil para asegurarnos de que la función es correcta, y en caso de incurrir en errores de tipos, entender la causa.

    + +

    Por otro lado, en ejemplos más complejos analizar los parámetros de las funciones usadas en la definición será indispensable para poder saber el tipo de retorno (por ejemplo en la presencia de polimorfismo).

    + +

    Ejemplo un poco mas heavy

    + +

    Siendo

    + +
    +
    +
    +      f x y z = (head y) > (map (\n -> n x) z)
    +
    +    
    +
    +
    + +

    Vamos a intentar hacer la inferencia de tipos. Primero tenemos que ver qué es f? f es una función que tiene 3 parámetros

    + +

    Ponemos 3 flechitas simples: ->

    + +
    +
    +
    +      f :: esto es el tipo de x -> esto es el tipo de y -> esto es el tipo de z -> esto es el tipo de lo que devuelve f
    +
    +    
    +
    +
    + +

    Como head :: [a] -> a, y tiene que ser una lista

    + +
    +
    +
    +      f :: esto es el tipo de x -> [???] -> esto es el tipo de z -> esto es el tipo de lo que devuelve f
    +
    +    
    +
    +
    + +

    Como map :: (a -> b) -> [a] -> [b], z tiene q ser una lista porque se usa como su segundo parámetro

    + +
    +
    +
    +      f :: esto es el tipo de x -> [???] -> [???] -> esto es el tipo de lo que devuelve f
    +
    +    
    +
    +
    + +

    La función (\n -> n x) que es primer parámetro del map recibe como parámetro cada elemento de la lista z, cada uno de esos elementos va a ser n. Y como n se está aplicando a x podemos inferir que n es una función, por lo que z es una lista de funciones

    + +
    +
    +
    +      f :: esto es el tipo de x -> [???] -> [??? -> ???] -> esto es el tipo de lo que devuelve f
    +
    +    
    +
    +
    + +

    Como x es el parámetro de n podemos inferir que x pertenece al dominio de n, por ende si el su dominio es de tipo a entonces x es de tipo a

    + +
    +
    +
    +      f :: a -> [???] -> [a -> ???] -> esto es el tipo de lo que devuelve f
    +
    +    
    +
    +
    + +

    Respiremos profundo… Asumimos que la imagen de las funciones de la lista es de tipo b, porque sólo a partir de map (\n -> n x) z no vemos nada que lo restrinja a tipos concretos, ni que deba ser del mismo tipo que su dominio al cual denominamos a

    + +
    +
    +
    +      f :: a -> [???] -> [a -> b] -> esto es el tipo de lo que devuelve f
    +
    +    
    +
    +
    + +

    Ahora pensemos en los parámetros de la función (>) :: Ord a => a -> a -> a que son (head y) y (map (\n -> n x) z):

    +
      +
    • Para poder comparar estas 2 cosas, ambas expresiones tienen que ser del mismo tipo
    • +
    • El map me da una lista de lo que devuelve (\n -> n x) sabemos que la imagen de (\n -> n x) es b entonces map (\n -> n x) z es de tipo [b]
    • +
    • Por ende (head y) también es de tipo [b]
    • +
    • Para que (head y) sea de tipo [b], y tiene que tener el tipo [[b]]
    • +
    • A su vez b debe pertenecer a la typeclass Ord (por la restricción impuesta por la función (>))
    • +
    + +
    +
    +
    +      f :: Ord b => a -> [[b]] -> [a -> b] -> esto es el tipo de lo que devuelve f
    +
    +    
    +
    +
    + +

    La función principal de f es (>), como la imagen de (>) al estar totalmente aplicado es Bool la imagen de f es Bool

    + +
    +
    +
    +      f :: Ord b => a -> [[ b ]] -> [a -> b] -> Bool
    +
    +    
    +
    +
    + +

    Ejemplo de parcial para pensar

    + +

    Tenemos esta función:

    + +
    +
    +
    +      f a b c d = maximoSegun (c d).filter (== snd a).map b
    +
    +    
    +
    +
    + +

    Y sabemos que:

    + +
    +
    +
    +      *Main> :t maximoSegun
    +maximoSegun :: Ord a1 => (a -> a1) -> [a] -> a
    +
    +    
    +
    +
    + +

    Cuál es el tipo de f? Ayudita: pensar cuál es la función principal en este ejemplo. Si no sabés bien qué está pasando, te recomendamos leer sobre notación point-free.

    + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/calidad-de-las-pruebas-unitarias.html b/wiki/articles/calidad-de-las-pruebas-unitarias.html new file mode 100644 index 0000000000..e1e8c31ac9 --- /dev/null +++ b/wiki/articles/calidad-de-las-pruebas-unitarias.html @@ -0,0 +1,330 @@ + + + + + + + + + + + Calidad de las pruebas unitarias + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Calidad de las pruebas unitarias +

    +
    + + + +
    +

    Introducción

    + +

    Las pruebas unitarias son una herramienta fundamental en el desarrollo de software. Con ellas es posible:

    + +
      +
    • Encarar refactors y correcciones con mayor seguridad
    • +
    • Mantener una especificación viva del sistema
    • +
    • Confirmar la presencia de errores del sistema
    • +
    • Guiar nuestro diseño (si se emplea TDD)
    • +
    + +

    El poder de las pruebas radica en que son, justamente, código (y no, por ejemplo, una especificación en un bibliorato), lo cual las vuelve facilmente automatizables. Y como se encuentra normalmente junto con el código productivo, los cambios en las especificaciones del mismo serán detectados rápidamente.

    + +

    Sin embargo, al tratarse de código, un desarrollo poco cuidado de los casos de pruebas puede introducir problemas similares a los que surgen con el código productivo en los siguiente aspectos:

    + +
      +
    • Expresividad: las pruebas se son ilegibles, los programadores no entienden lo que se está probando
    • +
    • Correctitud: las pruebas no validan lo que deberían, o, peor, lo hacen de forma incorrecta o no repetible.
    • +
    • Nivel de abstracción: las pruebas no tienen el nivel de abstracción suficiente, y repiten lógica, lo cual lleva a contar con muchos necesarios para una buena cobertura, pero casos extremadamente parecidos
    • +
    + +

    Lo cual llevará a severos problemas de mantenibilidad de los tests y a eslóganes y prácticas tan aviesas como “test que se rompe, test que se elimina”. Así nuestra preciada cobertura desaparecerá sin avisar.

    + +

    La moraleja es entonces que el nivel de calidad de las pruebas unitarias debe ser similar al del código productivo.

    + +

    Nivel de abstracción justo

    + +

    Tests abstractos

    + +

    Aserciones personalizadas

    + +

    Delegar apropiadamente

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/cannot-construct-the-infinite-type.html b/wiki/articles/cannot-construct-the-infinite-type.html new file mode 100644 index 0000000000..487298d401 --- /dev/null +++ b/wiki/articles/cannot-construct-the-infinite-type.html @@ -0,0 +1,366 @@ + + + + + + + + + + + Cannot construct the infinite type + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Cannot construct the infinite type +

    +
    + + + +
    +

    Advertecia: esto es un borrador

    + +

    El problema

    + +

    Que hace la siguiente función?

    + +

    autoAplicar funcion = funcion funcion

    + +

    OK, y que tipo tiene?

    + +

    autoAplicar :: (a->a) -> (a->a) ??

    + +

    Si lo cargamos

    + +

    Occurs check: cannot construct the infinite type: a = a -> a +When generalising the type(s) for `f'

    + +

    A que intenta generalizar?

    + +

    1. por x x, x es un funcion +2. x se le pasa un argumento, es una funcion de "un parametro"  +3. autoAplicar :: ( ? -> ? ) -> ? +4. por x x, x tiene que ser capaz de recibir una funcion de tipo x por parámetro. Entonces si x :: a -> ?, a == a -> ? +5. entonces x :: a -> ?  ==  (a -> ?) -> ?  ==  ( (a -> ?) -> ?) -> ? == (((a -> ?) -> ?) -> ?) -> ? .....

    + +

    Otra vuelta de tuerca

    + +

    Sin embargo…. si pudieramos desactivar el chequeo de tipos…. esto tiene sentido?

    + +

    autoAplicar id +id id +id

    + +

    Sí!

    + +

    Es más, si sólo lo desactivaramos para autoAplicar:

    + +

    autoAplicar id <- no tipa +id id <- tipa!! +id

    + +

    Moraleja: el sistema de tipos puede rechazar programas válidos

    + +

    type vs data/newtype

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/cantidad-de-parametros-de-una-funcion-en-haskell.html b/wiki/articles/cantidad-de-parametros-de-una-funcion-en-haskell.html new file mode 100644 index 0000000000..3931d291ab --- /dev/null +++ b/wiki/articles/cantidad-de-parametros-de-una-funcion-en-haskell.html @@ -0,0 +1,302 @@ + + + + + + + + + + + Cantidad de parametros de una funcion en haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Cantidad de parametros de una funcion en haskell +

    +
    + + + +
    +
      +
    1. REDIRECCIÓN Notación point-free
    2. +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ciclo-de-vida-de-un-objeto.html b/wiki/articles/ciclo-de-vida-de-un-objeto.html new file mode 100644 index 0000000000..a149044308 --- /dev/null +++ b/wiki/articles/ciclo-de-vida-de-un-objeto.html @@ -0,0 +1,341 @@ + + + + + + + + + + + Ciclo de vida de un objeto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Ciclo de vida de un objeto +

    +
    + + + +
    +

    Es importante reconocer el ciclo de vida de un objeto, ya que el estado que puede guardar un objeto depende de eso.

    + +

    Tipos de ciclo de vida puede haber mucho, a modo de ejemplo podemos mencionar tres muy comunes:

    + +
      +
    • Objetos permanentes, singletons, servicios. Son objetos que duran toda la vida del sistema (con variantes). En general nacen con el sistema y no pueden ser agregados nuevos, son compartidos por todos los usuarios del sistema. Estos son los que tienen el ciclo de vida más largo y no pueden tener ningún tipo de estado conversacional.
    • +
    • Objetos persistentes o entidades: Son los que representan los datos que guardamos de nuestro negocio, las entidades permanentes, por ejemplo en un video club me guardo los socios, las películas. Típicamente el ciclo de vida es darlos de alta, modificarlos, eventualmente se pueden dar de baja. A veces la baja es lógica.
    • +
    • Objetos transientes o procesos: Son los que guardan información sobre un proceso que se está llevando a cabo. El proceso puede ser tan corto como el procesamiento de un evento de teclado o mouse o un proceso de negocio que dura meses. Sin embargo los objetos persistentes no deberían guardar información de un proceso puntual, ya que esto es fuente de errores. En general los objetos con ciclos de vida más largos no pueden tener referencias a objetos de ciclo de vida más corto puntuales. Una vez terminados, estos objetos a veces se guardan como histórico. Un objeto persistente sí puede tener referencia a los procesos históricos o bien a los procesos en curso.
    • +
    + +

    En una aplicación web suelen aparecer objetos cuyo ciclo de vida está asociado a un request o a una session.

    + +

    Esto es análogo a un análisis de cardinalidad o normalización, se podría extender por ese lado.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/clase-abstracta-vs-interfaces.html b/wiki/articles/clase-abstracta-vs-interfaces.html new file mode 100644 index 0000000000..6405a48db0 --- /dev/null +++ b/wiki/articles/clase-abstracta-vs-interfaces.html @@ -0,0 +1,302 @@ + + + + + + + + + + + Clase abstracta vs interfaces + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Clase abstracta vs interfaces +

    +
    + + + +
    +
      +
    1. REDIRECCIÓN Clase abstracta vs interfaz
    2. +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/clase-abstracta-vs-interfaz.html b/wiki/articles/clase-abstracta-vs-interfaz.html new file mode 100644 index 0000000000..e678858399 --- /dev/null +++ b/wiki/articles/clase-abstracta-vs-interfaz.html @@ -0,0 +1,410 @@ + + + + + + + + + + + Clase abstracta vs interfaz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Clase abstracta vs interfaz +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Definiciones

    + +

    Clase abstracta

    + +

    Una clase abstracta es una clase que no tiene instancias. Su utilidad consiste en proveer estructura y comportamiento común a todas las subclases que heredan de ella.

    + +
    +
    +
    +      public abstract class Figura {
    +   final public boolean menorQue(Figura otraFigura) {
    +      return this.getArea() < otraFigura.getArea();
    +   }
    +   public abstract double getArea();
    +   public abstract double getPerimetro();
    +}
    +
    +    
    +
    +
    + +

    Si tenemos la clase Rectángulo, Círculo, etc. que heredan de Figura todas se benefician del comportamiento default para el método menorQue que permite comparar una figura con otra. Por otra parte los métodos que resuelven el área y el perímetro son abstractos, no se provee una implementación sino que deben ser codificados por las subclases.

    + +

    Interfaz

    + +

    Una interfaz permite especificar un contrato (formado por un conjunto de operaciones). Las clases que adhieren a ese contrato deben implementar esos métodos.

    + +
    +
    +
    +      /** Implementing this interface allows an object to be the target of
    + *  the "foreach" statement.
    + * @since 1.5
    + */
    +public interface Iterable<T> {
    +    /**
    +     * Returns an iterator over a set of elements of type T.
    +     * 
    +     * @return an Iterator.
    +     */
    +    Iterator<T> iterator();
    +}
    +
    +    
    +
    +
    + +

    En este ejemplo del lenguaje Java las clases que implementen la interfaz Iterable deben definir un método iterator(). Todos los métodos son abstractos, ya que la interfaz sólo declara la firma de cada uno de los métodos: nombre, parámetros que recibe, tipo que devuelve y excepciones que puede arrojar.

    + +

    Comparación

    + +

    Tanto la clase abstracta como la interfaz definen un tipo, pero mientras que el objetivo al definir una clase abstracta es reutilizar comportamiento, en la interfaz la idea principal es posibilitar el polimorfismo entre clases que no tienen cosas en común. Dependiendo del lenguaje, es posible que tengamos restricciones para crear métodos o atributos sobre una interfaz.

    + +

    Recordemos que en la mayoría de las tecnologías se trabaja únicamente con herencia simple (solamente es posible heredar de una única superclase), mientras que una clase puede tener múltiples tipos (implementar diferentes interfaces). Entonces en esos casos donde la herencia es una herramienta rígida, que permite una sola chance para ordenar la jerarquía de objetos, la interfaz puede resultar una alternativa viable.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/clases-anonimas-en-java.html b/wiki/articles/clases-anonimas-en-java.html new file mode 100644 index 0000000000..6cf0b31851 --- /dev/null +++ b/wiki/articles/clases-anonimas-en-java.html @@ -0,0 +1,630 @@ + + + + + + + + + + + Clases anonimas en java + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Clases anonimas en java +

    +
    + + + +
    +

    Motivación: ausencia de bloques

    + +

    La motivación más importante para entender las clases anónimas es la ausencia bloques (o closures) en el lenguaje Java. Java 8 recién es la primer versión que introduce un mecanismo de bloques (ver Lambdas_en_Java_8)

    + +

    Veamos un ejemplo:

    + +

    En smalltalk para seleccionar los elementos de una colección que cumplen cierta condición enviamos el mensaje “select:” Por ejemplo, para obtener las personas mayores de 18 años haríamos:

    + +

    personas select: [:p | p edad > 18 ]

    + +

    Ejemplo en Java Sin clases anónimas

    + +

    Cómo haríamos eso en java ?

    + +

    Primero que nada no existe un método “select” ni nada parecido en las colecciones (interfaz Collection). Así que tenemos que hacer el método nosotros.

    + +

    Hacemos un método estático como una utilidad, al que le tenemos que pasar la colección como parámetro.

    + +

    public class CollectionUtils { +   public static Collection` select(Collection`` coleccion, <<<< condicion >>>>) {` +`       ...` +`   }` +`}`

    + +

    Obviamente también tenemos que pasarle de alguna forma la condición !

    + +

    Ahora bien, en Java no existen los bloques o closures, con lo cual, la única opción que tenemos es pasar un objeto. Así que tenemos que modelar el concepto de Condicion.

    + +

    public interface Condicion { +  public boolean cumple(Object obj); +}

    + +

    Como la condición es lo que va a tener que implementar el “usuario” de este método, es decir quien quiera filtrar una colección, la definimos como una Interfaz de java, para no poner una restricción sobre una superclase (la otra opción sería que fuera una clase abstracta).

    + + + + + + + + +
    Fíjense que es un objeto que tiene una [http://en.wikipedia.org/wiki/Single_responsibility_principle[única responsabilidad]] bien identificada. Dado un objeto que le paso por parámetro me sabe decir si cumple o no con la condición.
    + +

    Entonces hacemos una primer implementación de nuestro ejemplo de filtrar mayores de 18 creando una clase normal que implemente esa interfaz.

    + +

    class MayorDe18Condicion implements Condicion { +   @Override +   public boolean cumple(Object obj) { +       return ((Persona) obj).getEdad() > 18; +   } +}

    + +

    Y para filtrar una colección

    + +

    personas = ... +CollectionUtils.select(personas, new MayorDe18Condicion());

    + +

    Incluso si usamos los imports estáticos de Java, podemos importar métodos estáticos de una clase, para no tener que llamarlos con el nombre de la clase, punto, y el método. Quedaría

    + +

    import static org.uqbar-project.CollectionUtils.select; +... +personas = ... +select(personas, new MayorDe18Condicion());

    + +

    Ok, igualmente sigue siendo mucho más burocrático y pesado que la implementación en smalltalk.

    + +

    Igualmente, lo que más nos molesta es que tenemos que crear una nueva clase por cada condición por la que querramos filtrar. Es bastante molesto eso. Ejemplo, queremos filtrar las personas casadas..

    + +

    class EsCasadaCondicion implements Condicion { +   @Override +   public boolean cumple(Object obj) { +       return ((Persona) obj).esCasada(); +   } +}

    + +

    Y luego

    + +

     casados = select(personas, new EsCasadaCondicion());

    + +

    Accediendo a referencias de otro Objeto (sin anónimas)

    + +

    Qué pasa si ahora queremos desde la condición utilizar una estado interno del objeto que está filtrando. Por ejemplo, desde una Empresa, queremos obtener sus empleados. Para eso, filtramos de la colección de personas a aquellas que trabajen para esta empresa.

    + +

    public class Empresa { +    +   public Collection getEmpleados() { +       return select(personas, new TrabajaEnCondicion(this)); +   }      +    +}

    + +

    Como se ve necesitamos pasarle la empresa a la condición. Es una condición que tiene estado. En este caso se pasa a sí mismo todo el objeto Empresa.

    + +

    class TrabajaEnCondicion implements Condicion { +   private Empresa empresa; +   public TrabajaEnCondicion(Empresa empresa) { +       this.empresa = empresa; +   } +   @Override +   public boolean cumple(Object obj) { +       return ((Persona) obj).getEmpleador() == this.empresa; +   } +}

    + +

    Cada vez más código ! :S Necesitamos declarar el atributo (estado interno) y recibirlo en el constructor.

    + +

    Bastante burocrático nuévamente. En smalltalk sería

    + +

     Empresa>>empleados +     ^personas select: [:p | (p empleador) = self]

    + +

    Accediendo a referencias locales (sin anónimas)

    + +

    Introducimos otra variante, otra situación normal.

    + +

    Queremos poder preguntarle a la empresa cuales son todos los empleados con más de “x” años. Es decir, no tenemos un valor único y fijo como antes, de 18, sino que lo recibimos como parámetro.

    + +

     public Collection getEmpleadosMayoresA(int anios) { +      return select(this.getEmpleados(), new MayoresA(anios)); + }

    + +

    De nuevo, se ve acá que tenemos que pasarle todo el estado que necesite la condición, como parámetro en la construcción. En este caso es un parámetro. Podría ser incluso una variable local.

    + +

    Aparece la Clase Anónima

    + +

    De lo anterior podemos concluir que la Condición en general va a ser un objetito más bien descartable, que lo uso para filtrar una colección en particular y luego lo descarto (más aún si tiene estado, no puedo reutilizar la condición “mayor a <23>” si luego tengo que buscar los mayores a <50>).

    + +

    Además, de que vamos a tener muchísimas clases implementaciones, según cuántos criterios de filtrado tengamos en el sistema.

    + +

    Esto es porque en realidad lo que necesitaríamos es expresar un pedacito de código nada más.

    + +

    Bien, como java no tiene bloques, para apalear un poco este problema, introduce la idea de clase anónima interna (del inglés anonymous inner classes). La idea es que en el cuerpo de un método pueda escribir una clase ahí mismo, “inline”, es decir sin necesidad de hacerlo en otro archivo. Como voy a implementar con esto un pedacito de código “descartable”, no hace falta que le ponga nombre a esta clase.

    + +

    Entonces, diréctamente instancio la interfaz (o clase abstracta), abro llaves, y ahí mismo la implemento.

    + +

    Ejemplo:

    + +

    public Collection getMayoresDe18() { +   Condicion mayoresA18 = new Condicion() { +       @Override +       public boolean cumple(Object obj) { +           return ((Persona) obj).getEdad() > 18; +       } +   }; +   return select(personas, mayoresA23); +}

    + +

    Este ejemplo es equivalente al primero que hicimos. Nótese que estamos haciendo

    + +

    variable =  

    + +

    La sintaxis es

    + +

     new Interface() { +     +    // implementación de la interface    +  + }

    + +

    Eso me da un objeto, que en este primer ejemplo lo asignamos a una variable local. Podríamos incluso no usar la variable local y diréctamente crearla para pasarla por parámetro al “select”.

    + +

    public Collection getMayoresDe18() { +   return select(personas, new Condicion() { +       @Override +       public boolean cumple(Object obj) { +           return ((Persona) obj).getEdad() > 18; +       } +     } +   ); +}

    + +

    Fíjense que es lo mismo, simplemente metimos todo el código desde el “new Cond… hasta el cierre de llaves de la calse, en el lugar del parámetro.

    + +

    Así, si lo miran con cariño (mucho cariño), se parece un poco a la implementación con bloques.

    + +

    Ojo, las reglas son las mismas que cuando definimos una clase en otro archivo. Como que:

    + +
      +
    • nos fuerza a implementar todos los métodos abstractos.
    • +
    • podemos sobrescribir un método (en caso de hacer una subclase anónima de una clase abstracta).
    • +
    • podemos llamar a super (pasa clase abstracta también).
    • +
    • etc.
    • +
    + +

    Sin embargo, a diferencia de una clase normal tiene algunas particularidades.

    + +

    Acceso a la instancia contenedora (Clase.this)

    + +

    La clase anónima además de poder acceder a su estado interno y mandarle mensajes a los parámetros que recibe en métodos, “ve” y puede también acceder al estado interno y mandarle mensajes a la instancia de la clase que la creó (es decir donde está el código definido).

    + +

    Rehagamos el ejemplo de la empresa

    + +

      public class Empresa { +      public Collection getEmpleados() { +          return select(personas, new Condicion() { +              @Override +              public boolean cumple(Object obj) { +                   return ((Persona) obj).getEmpleador() == Empresa.this; +              } +          }); +      } +  }

    + +

    Ven que acá estamos necesitamos comparar el empleador de la persona con la nosotros mismos. El problema es que estamos teniendo código dentro de una clase (anónima de Condicion) que está dentro de otra clase (Empresa). Entonces, no existe un único “this”. Tenemos dos. Como regla para toda clase anónima

    + +
      +
    • this: se refiere al objeto de la clase anónima, en nuestro caso sería la instancia de Condicion.
    • +
    • ClaseContenedora.this: se refiere al objeto instancia de la clase contenedora de esta anónima. En nuestro caso la Empresa.
    • +
    + +

    Así podríamos mandarle mensajes también

    + +

    ... +            return Empresa.this.esExEmpleado((Persona) obj); +...

    + +

    Donde “esExEmpleado(Persona p)” sería un método de la Empresa.

    + +

    O también accederle a una variable de instancia

    + +

    ... +            return ((Persona p)obj).getEmpleador().getNombre().equals(Empresa.this.nombre); +...

    + +

    Acceso a variables locales (final)

    + +

    Existe una particularidad de la implementación de Java, para recrear el último caso en que usábamos un parámetro “edad” para fitrar.

    + +

    Si escribieramos eso así:

    + +

    public Collection getMayoresA(int edad) { +   return select(personas, new Condicion() { +        @Override +        public boolean cumple(Object obj) { +            return ((Persona) obj).getEdad() > edad; +        } +   }); +}

    + +

    Tendrímos un error de compilación al hacer “> edad”, es decir al intentar acceder desde el código de la clase anónima al parámetro. Esto es porque la clase anónima si bien tiene acceso al “scope” de variables del método, solo puede acceder a aquellas variables que sean final, es decir que sean constantes, que no puedan cambiar. Esto es por una limitación de java. La solución sería agregar el modificador final al parámetro

    + +

    public Collection getMayoresA(final int edad) { +...

    + +

    Lo mismo sucede con referencias locales

    + +

    public Collection getMayoresAlPromedioDeEdad() { +   final int promedioDeEdad = this.calcularPromedioDeEdad(); +   return select(personas, new Condicion() { +        @Override +        public boolean cumple(Object obj) { +            return ((Persona) obj).getEdad() > promedioDeEdad; +        } +   }); +

    + +

    Nótese que la referencia local “promedioDeEdad” está declarada como final.

    + +

    Y si queremos cambiar el valor de la variable local (no puedo hacerla final) ??

    + +

    Bien, se puede resolver, sin embargo introduce burocracia. Para no cambiar el dominio vamos a tener que caer en un ejemplo de manejo de estructura.

    + +

    Supongamos que queremos obtener a un diccionario o Mapa con los empleados asociados a su edad expresada en decadas. Ej:

    + +

    20 >  Juan(23), Jose (27), Maria (21) +30 >  Yesi (30), Nico (36) +40 >  Carlos (48) +...

    + +

    Haríamos una iteración entre 20 y 70, por ejemplo, filtrando los empleados que tengan edad >= i y edad <= i + 9

    + +

    public Map<Integer, Collection> getEmpleadosPorEdad() { +    Map<Integer, Collection> empleadosPorEdades = new HashMap<Integer,Collection>(); +    for (int i = 20; i <= 70; i += 10) { +         Collection empleadosEncontrados = select(this.getEmpleados(), new Condicion() { +              @Override +              public boolean cumple(Object obj) { +                  int edad = ((Persona)obj).getEdad(); +                  return edad >= i && edad <= (i + 9) +              } +         }); +         empleadosPorEdades.put(i, empleadosEncontrados); +    } +}

    + +

    Bien, esto no compilaría, porque desde la clase anónima estamos usando la variable local “i”, que no es final. Si procedemos a ponerle “final” en la declaración, ahora no va a compilar el “for” en la parte del “i+=10” porque no se puede modificar una variable final. Entonces, estamos en una encrucijada. La forma de resolverla, es mover la clase anónima a otro método, donde la “i” sí la podemos declarar como final. Para esto podemos extraer el filtrado a otro método, y desde este pasarle la i como parámetro.

    + +

    public Map<Integer, Collection> getEmpleadosPorEdad() { +    Map<Integer, Collection> empleadosPorEdades = new HashMap<Integer,Collection>(); +    for (int i = 20; i <= 70; i += 10) { +         Collection empleadosEncontrados = this.getEmpleadosEnLaDecadaDel(i); +         empleadosPorEdades.put(i, empleadosEncontrados); +    } +}

    + +

    Y el nuevo método:

    + +

    public Collection getEmpleadosEnLaDecadaDel(final int i) { +    return select(this.getEmpleados(), new Condicion() { +          @Override +          public boolean cumple(Object obj) { +              int edad = ((Persona)obj).getEdad(); +              return edad >= i && edad <= (i + 9) +          } +    }); +}

    + +

    Como ven el parámetro “i” nunca cambia en este método, así que sí podemos declararlo como final. Mientras que en el for puede seguir siendo “no final”.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/clases-vs-instancias.html b/wiki/articles/clases-vs-instancias.html new file mode 100644 index 0000000000..71be326f95 --- /dev/null +++ b/wiki/articles/clases-vs-instancias.html @@ -0,0 +1,383 @@ + + + + + + + + + + + Clases vs instancias + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Clases vs instancias +

    +
    + + + +
    +

    En los lenguajes orientados a objetos que tienen clases (como Java, Xtend, Groovy, Scala, Smalltalk, Ruby, etc.) es frecuente como diseñadores preguntarnos si un determinado requerimiento se puede resolver con instancias o con clases.

    + +

    Ejemplo: tenemos tareas en un proyecto, a cada tarea le corresponden distintos impuestos

    + +
      +
    • el impuesto A es un 3% del costo de la tarea
    • +
    • el impuesto B representa un 2% del costo de la tarea
    • +
    • el impuesto C es un 1,5% del costo de la tarea
    • +
    + +

    Resolvemos el valor del impuesto A

    + +

    + +

    metodo valor(Tarea tarea)  +   tarea.costo * 0.03 +fin

    + +

    </code>

    + +

    Y a continuación el valor del impuesto B

    + +

    + +

    metodo valor(Tarea tarea)  +   tarea.costo * 0.02 +fin

    + +

    </code>

    + +

    Pero si analizamos con detenimiento veremos que los 3 impuestos comparten el mismo cálculo: la única diferencia es el % que se le aplica al costo de una tarea. No tiene sentido armar una jerarquía de clases para los impuestos:

    + +
      +
    • Impuesto +
        +
      • Impuesto A, método valor(Tarea)
      • +
      • Impuesto B, método valor(Tarea)
      • +
      • Impuesto C, método valor(Tarea)
      • +
      +
    • +
    + +

    Es mucho más conveniente generar una única abstracción impuesto que tenga el porcentaje como atributo:

    + +

    + +

    Clase Impuesto

    + +

    atributo porcentaje

    + +

    metodo valor(Tarea tarea)  +   tarea.costo * porcentaje +fin

    + +

    </code>

    + +

    Y no necesitamos tener las clases Impuesto A, B y C: si existieran, sólo se diferenciarian en el valor que almacenan en el porcentaje al construirse.

    + +

    Conviene trabajar con clases cuando hay comportamiento diferencial entre ellos, por el contrario cuando no hay diferencias en el comportamiento es preferible modelar esa solución con objetos. Una clase que no define comportamiento o atributos es sospechosa y como diseñadores deberíamos justificar una abstracción de esta naturaleza.

    + +

    Si apareciera un Impuesto D, que se calcula como el máximo entre $ 400 y el 5% del costo de la tarea, entonces sí tendría justificativo crear una nueva clase para modelar este impuesto, dado que el cálculo es diferente.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/clases.html b/wiki/articles/clases.html new file mode 100644 index 0000000000..39d536d98f --- /dev/null +++ b/wiki/articles/clases.html @@ -0,0 +1,459 @@ + + + + + + + + + + + Clases + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Clases +

    +
    + + + +
    +

    Motivación y Problema

    + +

    ¿Por qué necesito clases? Porque tengo varios objetos sospechosamente parecidos. Es decir,

    + +
      +
    • El comportamiento de varios objetos es igual. Es decir, no solo entienden los mismos mensajes, sino que tienen los mismos métodos (exactamente el mismo código).
    • +
    • sus atributos son los mismos, pero el estado interno es diferente. Es decir, si bien tienen los mismos atributos, éstos pueden apunta a diferentes objetos.
    • +
    • su identidad es diferente. Es decir, incluso si se comportan igual y se encuentran en el mismo estado, no son el mismo objeto.
    • +
    + +

    En conclusión, necesitamos una abstracción donde pongamos el código y los atributos en común de todos éstos objetos. Ésta abstracción es la clase, y cada objeto que se comporte igual (aunque tenga diferente estado interno) va a ser una instancia de esa clase.

    + +

    Podemos pensar a las clases como “Especies” y a las instancias como “individuos” de esas especies

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Especie (Clase)Individuo (instancia)
    Leonsimba
     nala
     mufasa
    Hienashenzi
     banzai
     ed
    Jabalípumba
    Zuricatatimon
    + +

    Cosas a recordar

    + +
      +
    • Todo objeto es siempre instancia de una y sólo una clase.
    • +
    • No se puede cambiar la clase de un objeto una vez creado.
    • +
    • Los métodos y atributos declarados en una clase son para sus instancias.
    • +
    + +

    Method Lookup

    + +

    Si el código está en la clase, entonces, ¿Cómo responde ahora un objeto a un mensaje? Con el Method Lookup. El method lookup es el mecanismo por el cual un objeto va a buscar el método correspondiente a su clase. (si no lo encuentra en su clase, no lo entiende). Revisar Herencia para conocer el Method Lookup completo.

    + +

    ¡Alto! ¿Quién soy yo?

    + +

    Si mi código ahora no está en mi objeto, sino en una clase, ¿¿Quién es self??

    + +

    self apunta siempre al objeto receptor del mensaje

    + +

    En éste envío de mensaje:

    + +

    simba.rugi()

    + +

    Si el método rugi() de la clase Leon usa self internamente, simba es self.

    + +

    ¿De dónde salen las instancias?

    + +

    Si definimos una clase, por ejemplo Leon, y queremos obtener a simba que es una instancia de Leon para poder mandarle mensajes, necesitamos crear la instancia a partir de la clase Leon. O sea que la clase tiene un segundo rol importante, no sirve sólo para definir el comportamiento y los atributos, también sirve para crear los objetos que luego usaremos en nuestro programa.

    + +

    Dependiendo del lenguaje, esto puede hacerse de formas distintas.

    + +

    En lenguajes en los cuales las clases son objetos, como es el caso de Smalltalk o Ruby por ejemplo, esto se hace mandándole un mensaje a la clase correspondiente. Por ejemplo:

    + +
    simba := Leon new.
    +mufasa := Leon new.
    +simba tuPapaEs: mufasa.
    +
    + +

    En otros lenguajes, como en Wollok o Java, las clases no son objetos y para crear instancias se utilizan herramientas específicas para la construcción de objetos. Por ejemplo:

    + +
    var simba = new Leon()
    +var mufasa = new Leon()
    +simba.tuPapaEs(mufasa)
    +
    + +

    Es importante entender que en las líneas del estilo unaVar := UnaClase new. o var unaVar = new UnaClase() pasan dos cosas, en el orden que se indica:

    + +
      +
    1. se crea un objeto instancia de la clase UnaClase.
    2. +
    3. se hace que la variable unaVar haga referencia al objeto recién creado.
    4. +
    + +

    Puede perfectamente instanciarse una clase y no asignar una variable en la misma línea con el nuevo objeto, siempre depende de lo que se esté tratando de hacer. Por ejemplo podría crearse un objeto dentro de un método y retornarlo directamente, o crearlo para mandarle un mensaje directamente.

    + +

    Si una instancia no es referenciada desde ningún lado, la misma ya no podrá ser usada, ya que nadie va a poder mandarle mensajes. Sin embargo no debemos preocuparnos por la memoria que ocupen estos objetos no olvidados, ya que ese trabajo es del Garbage Collector.

    + +

    Conclusión

    + +

    Una clase sirve de fábrica de objetos. Modela las abstracciones de mi dominio (los conceptos que nos interesan), permitiéndome definir el comportamiento y los atributos de las instancias.

    + +

    Dependiendo del lenguaje las clases pueden ser un objeto más que entiende mensajes pensados para ellas (este es el caso de Smalltalk, ver Variables y métodos de clase) o una construcción distinta del lenguaje que sólo existe para declarar el comportamiento de los objetos y darnos una forma de obtener nuevas instancias mediante el uso de herramientas de instanciación (no envíos de mensajes) como sucede en Wollok.

    + +

    Lo importante de todo esto es que las clases no son construcciones centrales como sí son los objetos, ya que impactan sólo a la definición y creación de los mismo, pero para el uso general del sistema, trabajamos de la misma forma que si las clases no estuvieran ahí. Es por eso que es en estos puntos en donde más difieren los lenguajes existentes, sin embargo la idea de objeto - mensaje se mantiene.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/coeficiente-de-felicidad-docente.html b/wiki/articles/coeficiente-de-felicidad-docente.html new file mode 100644 index 0000000000..fdb2c3e052 --- /dev/null +++ b/wiki/articles/coeficiente-de-felicidad-docente.html @@ -0,0 +1,312 @@ + + + + + + + + + + + Coeficiente de felicidad docente + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Coeficiente de felicidad docente +

    +
    + + + +
    +

    El Coeficiente de Felicidad Docente, a.k.a. CFD, mide la felicidad producida en una persona que se dedica a la enseñanza en función de la respuesta obtenida de parte de sus pupilos.

    + +

    Diversos factores pueden hacer variar este índice. Algunos ejemplos:

    + +
      +
    • Luego de machacar durante varias clases sobre la sintaxis de Smalltalk, resaltando que un envío de un mensaje SIEMPRE tiene que tener un objeto receptor, un ejercicio se entrega con una línea que dice “vola: 5”. Al haber sido completamente ignorado el aviso del docente y omitirse el objeto receptor en esa línea, el CFD se cae a pique.
    • +
    + + + +
      +
    • En un ejercicio en el que se pide resolver un problema X, un alumno logra combinar los conceptos vistos en clase para resolverlo. No contento con eso, considera que puede haber una mejor forma de resolver el problema porque su solución no le parece elegante y consulta al docente para que este lo oriente. El CFD cotiza en alza, debido a que el docente puede detectar que lo transmitido en clase fue asimilado por el alumno y, además, porque nota que el mismo intenta mejorar lo realizado y no sólo “zafar” el ejercicio.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/comidas.html b/wiki/articles/comidas.html new file mode 100644 index 0000000000..63fedc7013 --- /dev/null +++ b/wiki/articles/comidas.html @@ -0,0 +1,372 @@ + + + + + + + + + + + Comidas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Comidas +

    +
    + + + +
    +

    Salado

    + + + +

    Dulce

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/como-bajar-y-correr-un-ejemplo-en-wicket.html b/wiki/articles/como-bajar-y-correr-un-ejemplo-en-wicket.html new file mode 100644 index 0000000000..68cd3c3f68 --- /dev/null +++ b/wiki/articles/como-bajar-y-correr-un-ejemplo-en-wicket.html @@ -0,0 +1,400 @@ + + + + + + + + + + + Como bajar y correr un ejemplo en wicket + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Como bajar y correr un ejemplo en wicket +

    +
    + + + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    + +

    + +

    Primer proyecto con Wicket

    + +
      +
    • Bajar alguno de los ejemplos, por ejemplo éste
    • +
    • Importarlo como Maven Project
    • +
    + + + +

    Incorporar la app al web server

    + +
      +
    1. Posicionarse en la solapa Servers: Window > Show view > Other… Server
    2. +
    3. Luego botón derecho sobre Server > Add and Remove…
    4. +
    5. Pasar la aplicación del container Available a Configured (seleccionarla y luego presionar el botón Add>)
    6. +
    7. Finish
    8. +
    9. Reiniciar el servidor (botón derecho > Restart in Debug o Restart)
    10. +
    + +

    Acceder desde el browser a la direccion

    + +
    +
    +
    +      http://localhost:8080/aplicacion-web-en-cuestion/
    +
    +    
    +
    +
    + +

    Links relacionados

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/como-crear-una-subclase-en-squeak.html b/wiki/articles/como-crear-una-subclase-en-squeak.html new file mode 100644 index 0000000000..1c65382941 --- /dev/null +++ b/wiki/articles/como-crear-una-subclase-en-squeak.html @@ -0,0 +1,367 @@ + + + + + + + + + + + Como crear una subclase en squeak + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Como crear una subclase en squeak +

    +
    + + + +
    +

    Para crear una subclase hay dos formas:

    + +

    Forma A

    + +
      +
    1. En un class browser ó System Browser ctrl-click (click derecho en Pharo) sobre la superclase, les abre un menú contextual. Ahí “more…”->“subclass template” (en Pharo sin el more..).
    2. +
    3. Les va a aparecer un texto parecido a este (en mi ejemplo tomé como superclase a la clase Ave):
    4. +
    + +

    Ave subclass: #NameOfSubclass +    instanceVariableNames: '' +    classVariableNames: '' +    poolDictionaries: '' +    category: 'PDEP-EjemploGolondrinas'

    + +
      +
    1. Reemplazar “#NameOfSubclass” por el nombre de la clase que quieran (ojo hay que dejar el “#”)
    2. +
    3. Pueden agregar variables de instancia y de clase (entre comillas simples y separadas por espacios).
    4. +
    5. Elegir la categoría que queran, por defecto les va a aparecer la misma categoría que la superclase (les conviene poner todas sus clases en una categoría propia (o un varias categorías propias si quieren diferenciarlas de alguna manera). Si ponen un nombre de categoría nuevo les va a crear la categoría junto con la clase.
    6. +
    7. Salvar (ctrl+s o ctrl+click, accept… (*))
    8. +
    + +

    Si ven bien los pasos 3-5 son para cualquier clase, la gran diferencia es que para crear una clase común dice “Object” en lugar de “Ave” (es decir, todas nuestras clases son subclases de Object, salvo que yo le indique alguna otra más específica).

    + +

    Forma B

    + +

    Una forma que puede resultar más sencilla es directamente copiar el texto que está arriba en la sección de código del Class Browser (eso reemplaza los puntos 1 y 2) y luego modificarlo y salvarlo (igual a los pasos 3-6).

    + +

    (Asegúrense de borrar todo lo que haya en la sección de código antes, es decir, tiene que ser el único texto en ese lugar, lo modifican y lo graban, voilá).

    + +
      +
    1. Una cosa que puede resultar difícil del squeak es que hay que usar siempre ctrl-click en lugar de lo que los usuarios windows están acostumbrados como “click derecho”… para configurar eso: Menú Ppal -> system preferences -> preferences -> escriben en el campito de texto “swap” y le tildan la opcion “swap mouse buttons” -> save.
    2. +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/como-empezar.html b/wiki/articles/como-empezar.html new file mode 100644 index 0000000000..2005c26548 --- /dev/null +++ b/wiki/articles/como-empezar.html @@ -0,0 +1,1520 @@ + + + + + + + + + + + Como contribuir a la wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Como contribuir a la wiki +

    +
    + + + +
    +

    Introducción

    + +

    Esta sección describe brevemente la sintaxis de markdown que se usa en la wiki, además de mostrar +algunas cosas extras que componen a la wiki.

    + +

    Para hacer modificaciones simples con un articulo, basta con modificar desde github directamente el ariculo en cuestion. +En caso de que se desee modificar

    + +

    La carpeta wiki/articles contiene todos los articulos de la wiki, incluyendo esta sección.

    + +

    Requerimientos

    + +

    Para testear localmente se necesitan los siguientes requerimientos previos.

    + +
      +
    • Ruby 2.5.0
    • +
    • Bundler
    • +
    • yarn
    • +
    • imagemagick
    • +
    • python
    • +
    + +

    Para instalar las dependencias de ruby adicionales ejecutar:

    + +
    +
    +
    +      bundle install
    +
    +    
    +
    +
    + +

    Este proyecto utiliza Jekyll, para levantar una instancia local una vez instaladas las dependencias habrá que instalar +las dependencias adicionales mediante yarn:

    + +
    +
    +
    +      yarn install
    +
    +    
    +
    +
    + +

    Una vez ya resueltas todas las dependencias se puede levantar el entorno mediante:

    + +
    +
    +
    +      jekyll s --i
    +
    +    
    +
    +
    + +

    Esto arma un build local y una vez completado este proceso levanta localmente la instancia. De aquí en más se podrá hacer modificaciones localmente, y el servidor actualizará los cambios automáticamente (es lo que hace el flag --i de incremental).

    + +

    Tener en cuenta que ante cualquier modificación fuera de los artículos, como los plugins, se necesitará ejecutar un nuevo build de jekyll. (El servidor se levantará por default en localhost:4000)

    + +

    Modificando

    + +

    Una vez levantado localmente nuestra instancia de jekyll con la wiki, podremos modificar los articulos que componen +la wiki en sí. Todos los articulos están situados en ./wiki/articles, se pueden tener subdirectorios tambien, como +por ejemplo .wiki/articles/sub/Subpage.html

    + +

    Todos los articulos tienen que tener el header yml:

    + +
    +
    +
    +      ---
    +layout: article
    +title: <title>
    +---
    +
    +    
    +
    +
    + +

    Despues de eso el formato de los articulos estan en markdown, todos los articulos deben tener el layout article +El campo title es utilizado para Describir el titulo principal en el artículo.

    + +

    Syntaxis adicional

    + +

    Linkeando artículos

    + +

    Se puede linkear un artículo de dos maneras

    + +
      +
    1. Se puede utilizar el plugin link_article: +
           <a class="link article_link" href="/wiki/articles/como-empezar.html">como empezar</a>
      +
      +
    2. +
    3. O Hacerlo en markdown directamente: +[The guide for newbies](/wiki/articles/como-empezar.html)
    4. +
    + +

    Ambos enfoques generan el mismo html, solamente que en el primero se omite la extensión y los guiones medios (-).

    + +

    Embebiendo gists

    + +

    Se puede embeber gists publicos de la siguiente manera:

    + +
    +
    +
    +      gist bossiernesto/97285bb96f1da185858af7de5cdee978
    +
    +    
    +
    +
    + +

    Esto genera:

    + + + + +

    Bibliografía

    + +

    Se puede citar referencias mediante la sintaxis

    + +
    +
    +
    +          cite "nombre de cita"
    +
    +    
    +
    +
    +

    esto genera:

    + +

    + (Burmako) +

    + +

    Ahora existe un repositorio central de bibliografia en _bibliography/wikibiblio.bib. Todas las referencias deben estar +anotadas con una sintaxis BibTex, la misma se puede obtener en algun sitio que nos brinde este tipo de formato como CiteSeerx

    + +

    Si se quiere mostrar toda la bibliografía del repositorio se tiene que usar la anotación bibliography

    + +
    1. Flanagan, David, and Yukihiro Matsumoto. The Ruby Programming Language. O’Reilly Media, 2008.
    2. +
    3. Burmako, Eugene. Scala Macros: Let Our Powers Combine! On How Rich Syntax and Static Types Work with Metaprogramming.
    + +

    Ahora si queremos solo mostrar las bibliografía citada, utilizaremos la anotación bibliography --cited

    + +
      +
    1. + Burmako, Eugene. Scala Macros: Let Our Powers Combine! On How Rich Syntax and Static Types Work with Metaprogramming. +
    2. +
    + +

    Para mayores referencias ver la siguiente sección

    + +

    Embeber markdown remoto

    + +

    Se puede embeber markdown en formato raw de un repositorio externo de la organizacion mediante la notación

    + +

    ` remote_markdown `

    + +
    + Cuando se utilice esta funcionalidad, verificar previamente que renderiza el link y el origen del mismo. Se recomienda + que sea de un sitio como Github o Gitlab y que sea mediante una url por https. +
    + +

    Embebiendo código

    + +

    Se puede incluir código con el triple backtrick. Esta wiki usa highlightjs para syntax highlighting. +highlightjs tiene muchos esquemas y +aquí hay algunos ejemplos.

    + +
    +Hay que tener en cuenta que se debe configurar el idioma cuando se utiliza la sintaxis de triple \`. +El resaltado no funciona si no hay un idioma especificado. +
    + +

    Ejemplo:

    + +
    +
    +
    +          class Bleh
    +        def a(b)
    +            b + 1
    +        end
    +    end
    +
    +    
    +
    +
    + +

    Alertas

    + +

    Hay distinto tipos de alertas:

    + +
    + secondary +
    + +
    + info +
    + +
    + success +
    + +
    + warning +
    + +
    + alert +
    + +

    Cada tipo de alerta tiene un color distinto, la sintaxis es la siguiente:

    + +
    +
    +
    +        "<div data-alert class='alert-box secondary' tabindex='0' aria-live='assertive' role='alertdialog'>"
    +    your text
    +  "</div>"
    +
    +    
    +
    +
    + +

    Donde <kind> puede ser “secondary”, “info”, “success “, “warning” or +“alert”.

    + +

    Se agrega ahora el readme de jekyll-scholar con las referencias

    + +

    Jekyll-Scholar

    +

    + + CI + +

    + +

    Jekyll-Scholar is for all the academic bloggers out there. It is a set of +extensions to Jekyll, the awesome, blog aware, static +site generator; it formats your bibliographies and reading lists for the web +and gives your blog posts citation super-powers.

    + +

    Already using Jekyll-Scholar and interested to help out? Please get in touch with us if you would like to become a maintainer!

    + +

    Installation

    + +
    +
    +
    +      $ [sudo] gem install jekyll-scholar
    +
    +    
    +
    +
    + +

    Or add it to your Gemfile:

    + +
    +
    +
    +      gem 'jekyll-scholar', group: :jekyll_plugins
    +
    +    
    +
    +
    + +

    Github Pages

    + +

    Note that it is not possible to use this plugin with the + default Github pages workflow. +Github does not allow any but a few select plugins to run for security reasons, +and Jekyll-Scholar is not among them. +You will have to generate your site locally and push the results to the master resp. gh-pages +branch of your site repository. +You can keep sources, configuration and plugins in a separate branch; see e.g. + here +for details.

    + +

    Alternatively, you can use a Github Actions called jekyll-action to deploy your site to Github Pages

    + +

    Usage

    + +

    Install and setup a new Jekyll directory (see the +Jekyll-Wiki for detailed +instructions). To enable the Jekyll-Scholar add the following statement +to a file in your plugin directory (e.g., to _plugins/ext.rb):

    + +
    +
    +
    +      require 'jekyll/scholar'
    +
    +    
    +
    +
    + +

    Alternatively, add jekyll-scholar to your gem list in your Jekyll +configuration:

    + +
    +
    +
    +      plugins: ['jekyll/scholar']
    +
    +    
    +
    +
    + +

    Configuration

    + +

    In your Jekyll configuration file you can adjust the Jekyll-Scholar settings +using the scholar key. For example, the following sets the bibliography style +to modern-language-association.

    + +
    +
    +
    +      scholar:
    +  style: modern-language-association
    +
    +    
    +
    +
    + +

    The table below describes some commonly used configuration options. For a +description of all options and their defaults, see +defaults.rb.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OptionDefaultDescription
    styleapaIndicates the style used for the bibliography and citations. You can use any style that ships with CiteProc-Ruby by name (e.g., apa, chicago-fullnote-bibliography) which is usually the filename as seen here without the .csl ending; note that you have to use dependent/style if you want to use one from that directory. Alternatively you can add a link to any CSL style (e.g., you could link to any of the styles available at the official CSL style repository).
    localeenDefines what language to use when formatting your references (this typically applies to localized terms, e.g., ‘Eds.’ for editors in English).
    source./_bibliographyIndicates where your bibliographies are stored.
    bibliographyreferences.bibIndicates the name of your default bibliography. For best results, please ensure that your bibliography is encoded as ASCII or UTF-8. A string that contains a * will be passed to Dir::glob, so **/*.bib{,tex} will find all files named *.bib and *.bibtex under source.
    allow_locale_overridesfalseWhen true, allows the language entry in the BibTex to override the locale setting for individual entries. When the language is missing it will revert back to locale. The language value should be encoded using the two-letter ISO 639-1 standard. Ex. English = ‘en’, Spanish = ‘es’.
    sort_bynoneSpecifies if and how bibliography entries are sorted. Entries can be sorted on multiple fields, by using a list of keys, e.g. year,month. Ordering can be specified per sort level, e.g. order: descending,ascending will sort the years descending, but per year the months are ascending. If there are more sort keys than order directives, the last order entry is used for the remaining keys.
    orderascendingSpecifies order bibliography entries are sorted in. Can be ascending or descending. Ordering can be specified per sort level, e.g. descending,ascending will sort in descending on the first key then ascending order on the second key. If there are more sort keys than order directives, the last order entry is used for the remaining keys.
    group_bynoneSpecifies how bibliography items are grouped. Grouping can be multi-level, e.g. type, year groups entries per publication type, and within those groups per year.
    group_orderascendingOrdering for groups is specified in the same way as the sort order. Publication types – specified with group key type, can be ordered by adding type_order to the configuration. For example, type_order: [article,techreport] lists journal articles before technical reports. Types not mentioned in type_order are considered smaller than types that are mentioned. Types can be merge in one group using the type_aliases setting. By default phdthesis and mastersthesis are grouped as thesis. By using, for example, type_aliases: { inproceedings: article}, journal and conference articles appear in a single group. The display names for entry types are specified with type_names. Names for common types are provided, but they can be extended or overridden. For example, the default name for article is Journal Articles, but it can be changed to Papers using type_names: { article: Papers }.
    bibtex_filterslatex,smallcaps,superscriptConfigures which BibTeX-Ruby formatting filters values of entries should be passed through. The default latex filter converts LaTeX character escapes into unicode, smallcaps converts the \textsc command into a HTML <font style=\"font-variant: small-caps\"> tag, and superscript which converts the \textsuperscript command into a HTML <sup> tag.
    raw_bibtex_filters` `Configures which BibTeX-Ruby formatting filters the raw BiBTeX entry (i.e. that available through {{ entry.bibtex }}) should be passed through. This can be used to e.g. strip excess newlines by using the linebreaks filter.
    + +

    Bibliographies

    + +

    Once you have loaded Jekyll-Scholar, all files with the extension .bib or +.bibtex will be converted when you run Jekyll (don’t forget to add a YAML +header to the files); the file can contain regular HTML or Markdown and +BibTeX entries; the latter will be formatted by Jekyll-Scholar according to +the citation style and language defined in your configuration file.

    + +

    For example, if you had a file bibliography.bib in your root directory:

    + +
    +
    +
    +      ---
    +---
    +References
    +==========
    +
    +@book{ruby,
    +  title     = {The Ruby Programming Language},
    +  author    = {Flanagan, David and Matsumoto, Yukihiro},
    +  year      = {2008},
    +  publisher = {O'Reilly Media}
    +}
    +
    +    
    +
    +
    + +

    It would be converted to bibliography.html with the following content:

    + +
    +
    +
    +      <h1 id='references'>References</h1>
    +
    +<p>Flanagan, D., &#38; Matsumoto, Y. (2008). <i>The Ruby Programming Language</i>. O&#8217;Reilly Media.</p>
    +
    +    
    +
    +
    + +

    This makes it very easy for you to add your bibliography to your Jekyll-powered +blog or website.

    + +

    If you are using other converters to generate your site, don’t worry, you can +still generate bibliographies using the bibliography tag. In your site +or blog post, simply call:

    + +
    +
    +
    +      {% bibliography %}
    +
    +    
    +
    +
    + +

    This will generate your default bibliography; if you use multiple, you can +also pass in a name to tell Jekyll-Scholar which bibliography it should render.

    + +

    Let’s say you have two bibliographies stored in _bibliography/books.bib and +_bibliography/papers.bib; you can include the bibliographies on your site +by respectively calling {% bibliography --file books %} and +{% bibliography --file papers %}. For example, you could have a file references.md +with several reference lists:

    + +
    +
    +
    +      ---
    +title: My References
    +---
    +
    +{{ page.title }}
    +================
    +
    +The default Bibliography
    +------------------------
    +
    +{% bibliography %}
    +
    +Secondary References
    +--------------------
    +
    +{% bibliography --file secondary %}
    +
    +    
    +
    +
    + +

    Finally, the bibliography tag supports an optional filter parameter. This +filter takes precedence over the global filter defined in your configuration.

    + +
    +
    +
    +      {% bibliography --query @*[year=2013] %}
    +
    +    
    +
    +
    + +

    The example above would print a bibliography of all entires published in +the year 2013. Of course you can also combine the file and filter parameters +like this:

    + +
    +
    +
    +      {% bibliography -f secondary -q @*[year=2013] %}
    +
    +    
    +
    +
    + +

    This would print the publications from 2013 of the bibliography at +_bibliography/secondary.bib.

    + +

    For more details about filters, see the corresponding section below or +consult the BibTeX-Ruby +documentation.

    + +

    If you need to limit the number of entries in your bibliography, you can +use the --max option:

    + +
    +
    +
    +      {% bibliography --max 5 %}
    +
    +    
    +
    +
    + +

    This would generate a bibliography containing only the first 5 entries +of your bibliography (after query filters and sort options have been +applied). Limiting entries is disabled if grouping is active.

    + +

    Return number of publications in bibliography

    + +

    The bibliography_count returns the number of items that would be +rendered in a bibliography. This tag accepts the same parameters as the +bibliography tag.

    + +
    +
    +
    +      {% bibliography_count -f references --query @book[year <=2000] %}
    +
    +    
    +
    +
    + +

    See #186 +for further examples.

    + +

    Bibliography Template

    + +

    Your bibliography is always rendered as an ordered list. Additionally, +each reference is wrapped in an HTML tag (span by default but you can +change this using the reference_tagname setting) with the cite key +as id. The reference string itself is governed by the rules in your +CSL style but you can also customize the main template a little bit. +By default, the template is {{reference}} – this renders only the +reference tag. The template uses Liquid to render and, in +addition to the reference, exposes the cite-key (as key), the +entry’s type, the index in the bibliography, and the link to +file repository as link. Thus, you could +customize the template in your configuration as follows:

    + +
    +
    +
    +      scholar:
    +  bibliography_template: <abbr>[{{key}}]</abbr>{{reference}}
    +
    +    
    +
    +
    + +

    This would be processed into something like:

    + +
    +
    +
    +      <li><abbr>[ruby]</abbr><span id="ruby">Matsumoto, Y. (2008). <i>The Ruby Programming Language</i>. O&#8217;Reilly Media.</span></li>
    +
    +    
    +
    +
    + +

    If you have more complex requirements, it quickly becomes tedious to +have the template inside the configuration; for this reason, you can +also put the bibliography template into your layouts directory. Jekyll-Scholar +will load this template if the option set in your configuration matches +an existing layout (without the file extension). That is to say, if you set:

    + +
    +
    +
    +      scholar:
    +  bibliography_template: bib
    +
    +    
    +
    +
    + +

    And there is a file _layouts/bib.html (or with another extension) the +contents of this file will be used as the template. Please note that it is +important for this file to contain the YAML front matter! For example, this +would be a more complex template file:

    + +
    +
    +
    +      ---
    +---
    +{{ reference }}
    +
    +{% if entry.abstract %}
    +<p>{{ entry.abstract }}</p>
    +{% endif %}
    +
    +<pre>{{ entry.bibtex }}</pre>
    +
    +    
    +
    +
    + +

    You can also override the default bibliography template, by passing the +--template or -T option parameter to the bibliography tag.

    + +

    Citations

    + +

    If you want to reference books or papers from your bibliography in your blog +posts, Jekyll-Scholar can help you, too. Simply use the cite tag with +the appropriate key of the item you want to cite and Jekyll-Scholar will +create a formatted citation reference for you. For a quick example, take +following blog post:

    + +
    +
    +
    +      ---
    +layout: default
    +title: A Blogging Scholar
    +---
    +
    +{{ page.title }}
    +================
    +
    +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
    +incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
    +nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
    +Duis 'aute irure dolor in reprehenderit in voluptate' {% cite derrida:purveyor %}
    +velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
    +cupidatat non proident, 'sunt in culpa qui officia deserunt mollit anim id est
    +laborum' {% cite rabinowitz %}.
    +
    +Duis 'aute irure dolor in reprehenderit in voluptate' {% cite breton:surrealism %}
    +velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
    +cupidatat non proident, 'sunt in culpa qui officia deserunt mollit anim id est
    +laborum' {% cite rainey %}.
    +
    +References
    +----------
    +
    +{% bibliography %}
    +
    +    
    +
    +
    + +

    Note that this will print your entire bibliography in the Reference section. +If you would like to include only those entries you cited on the page, pass +the cited option to the bibliography tag:

    + +
    +
    +
    +      {% bibliography --cited %}
    +
    +    
    +
    +
    + +

    By default, the --cited option will still sort your bibliography if you set +the sort option. Especially for styles using citation numbers, this is usually +not the desired behaviour. In such cases you can use --cited_in_order instead +of --cited and your bibliography will contain all cited items in the order +they were cited on the page.

    + +

    For longer quotes, Jekyll-Scholar provides a quote tag:

    + +
    +
    +
    +      {% quote derrida:purveyor %}
    +Lorem ipsum dolor sit amet, consectetur adipisicing elit,
    +sed do eiusmod tempor.
    +
    +Lorem ipsum dolor sit amet, consectetur adipisicing.
    +{% endquote %}
    +
    +    
    +
    +
    + +

    For example, this could be rendered as:

    + +
    +
    +
    +      <blockquote>
    +  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,<br/>
    +  sed do eiusmod tempor.</p>
    +  <p>Lorem ipsum dolor sit amet, consectetur adipisicing.</p>
    +  <cite>
    +    <a href="#derrida:purveyor">(Derrida, 1975)</a>
    +  </cite>
    +</blockquote>
    +
    +    
    +
    +
    + +

    Multiple citation

    + +

    You can cite multiple items in a single citation by referencing all ids +of the items you wish to quote separated by spaces. For example, +{% cite ruby microscope %} would produce a cite tag like:

    + +
    +
    +
    +      <a href="#ruby">(Flanagan &amp; Matsumoto 2008; Shaughnessy 2013)</a>
    +
    +    
    +
    +
    + +

    Citations when there’s more than one bibliography

    + +

    Let’s return to the example above where you have two bibliographies stored +in _bibliography/books.bib and _bibliography/papers.bib. We also must +have the main bibliography, e.g., _bibliography/references.bib. As we +know from above, it’s possible to use bibliographies other than the main +bibliography by calling {% bibliography --file books %} or +{% bibliography --file papers %}.

    + +

    Though what if we want to cite an article that’s not in the main bibliography? +We use the same approach as above; to cite an article in the books.bib +bibliography, we simply call {% cite ruby --file books %}

    + +

    Suppressing author names

    + +

    Sometimes you want to suppress author names in a citation, because the +name has already been mentioned in your text; for such cases Jekyll-Scholar +provides the --suppress_author option (short form: -A): +...as Matz explains {% cite ruby -A -l 42 %} would produce something +like: ...as Matz explains (2008, p. 42).

    + +

    Page numbers and locators

    + +

    If you would like to add page numbers or similar locators to your citation, +use the -l or --locator option. For example, {% cite ruby --locator 23-5 %} would +produce a citation like (Matsumoto, 2008, pp. 23-5).

    + +

    When quoting multiple items (see above) you can add multiple locators after +the list of ids. For example, {% cite ruby microscope -l 2 -l 24 & 32 %}.

    + +

    Page is the default locator, however, you can indicate the type of locator +by adding a -L or --label option (one for each locator) for instance, +{% cite ruby microscope --label chapter --locator 3 -L figure -l 24 & 32 %} +produces something like: (Matsumoto, 2008, chap. 3; Shaughnessy, 2013, figs. 24 & 32).

    + +

    Displaying formatted references

    + +

    If you want to display the full formatted reference entry, you can use the +reference tag. For example, given the following Bibtex entry,

    + +
    +
    +
    +      @book{ruby,
    +  title     = {The Ruby Programming Language},
    +  author    = {Flanagan, David and Matsumoto, Yukihiro},
    +  year      = {2008},
    +  publisher = {O'Reilly Media}
    +}
    +
    +    
    +
    +
    + +

    using {% reference ruby %} anywhere in your page, it will print +“Flanagan, D., & Matsumoto, Y. (2008). The Ruby Programming Language.. +O’Reilly Media” (the exact result depends on your formatting style).

    + +

    The reference tag accepts the same –file/-f parameter as the bibliography +tag. This can be handy if you want to use a special BibTeX file as input for +a specific page. As an example, the tag

    + +
    +
    +
    +      {% reference ruby --file /home/foo/bar.bib %}
    +
    +    
    +
    +
    + +

    will attempt to read the key ruby from file /home/foo/bar.bib. It will not +fallback to the default BibTeX file.

    + +

    Citation pointing to another page in your site

    +

    In some cases, you might want your citation to link to another page on your cite (ex. a separate works cited page). As a solution, add a relative path to your scholar configurations:

    + +
    +
    +
    +          scholar:
    +      relative: "/relative/path/file.html"
    +
    +    
    +
    +
    + +

    Multiple bibliographies within one document (like multibib.sty)

    + +

    When you have multiple {% bibliography %} sections in one file, +Jekyll-Scholar will generate several lists containing the same +publications that have the same id attributes. As a result, when you +cite a reference the link to an id attribute cannot be resolved +uniquely. Your browser will always take you take you to the first +occurrence of the id. Moreover, valid HTML requires unique id +attributes. This scenario may happen, for example, if you cite the +same reference in different blog posts, and all of these posts are +shown in one html document.

    + +

    As a solution, Jekyll-Scholar provides the --prefix tag. In your +first post you might cite as

    + +
    +
    +
    +      ---
    +title: Post 1
    +---
    +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
    +incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
    +nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
    +Duis 'aute irure dolor in reprehenderit in voluptate'
    +{% cite derrida:purveyor --prefix post1 %} velit esse cillum
    +dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
    +non proident, 'sunt in culpa qui officia deserunt mollit anim id
    +est laborum' {% cite rabinowitz --prefix post1 %}.
    +
    +References
    +----------
    +
    +{% bibliography --cited --prefix post1 %}
    +
    +    
    +
    +
    + +

    For the second blog post you would cite as follows:

    + +
    +
    +
    +      ---
    +title: Post 2
    +---
    +Duis 'aute irure dolor in reprehenderit in voluptate'
    +{% cite rabinowitz --prefix post2 %} velit esse cillum
    +dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
    +non proident, 'sunt in culpa qui officia deserunt mollit anim id
    +est laborum' {% cite rainey --prefix post2  %}.
    +
    +References
    +----------
    +
    +{% bibliography --cited --prefix post2 %}
    +
    +    
    +
    +
    + +

    Even though both posts cite ‘rabinowitz’, both citations will be +assigned unique identifiers linking to the respective references +section, although both posts will be rendered into a single HTML +document.

    + +

    Add a custom class for the citation reference

    +

    By default Jekyll Scholar generate a link with a class:

    + +
    +
    +
    +      <a href="#ruby" class="citation">(Derrida, 1975)</a>
    +
    +    
    +
    +
    + +

    You can custom this class in your configuration:

    + +
    +
    +
    +      scholar:
    +  cite_class: citation
    +
    +    
    +
    +
    + +

    File Repositories

    + +

    File repository support was added to Jekyll-Scholar starting at version +2.0. Currently, if you have a folder in your site that contains PDF or +Postscript files of your papers, you can use the configuration option +repository to indicate this directory. When generating bibliographies, +Jekyll-Scholar will look in that folder to see if it contains a filename +matching each entry’s BibTeX key: if it does, the path to that file +will be exposed to the bibliography template as the link property.

    + +

    Since version 4.1.0 repositories are not limited to PDF and PS files. +These files are mapped to the links property in your bibliography +template. Here is an example of template that utilizes this feature +to link to supporting material in a ZIP archive:

    + +
    +
    +
    +      {{ reference }} [<a href="{{links.zip}}">Supporting Materials</a>]
    +
    +    
    +
    +
    + +

    Since version 5.9.0, Jekyll-Scholar matches files which begin with a BibTeX key +and are immediately followed by a delimiter (default: “.”). All text proceeding +the delimiter is treated as the file extension. For example, if two files named +key.pdf and key.slides.pdf are found, {{links.pdf}} and +{{links['slides.pdf']}} will both be populated. You can use the configuration +option repository_file_delimiter to change the default delimiter.

    + +

    Detail Pages

    + +

    If your layouts directory contains a layout file for bibliography details +(the details_layout configuration options), Jekyll-Scholar will generate +a details page for each entry in you main bibliography. That is to say, if +your bibliography contains the following entry:

    + +
    +
    +
    +      @book{ruby,
    +  title     = {The Ruby Programming Language},
    +  author    = {Flanagan, David and Matsumoto, Yukihiro},
    +  year      = {2008},
    +  publisher = {O'Reilly Media}
    +}
    +
    +    
    +
    +
    + +

    Then a page ‘bibliography/ruby.html’ will be generated according to your +details page layout. In the layout file, you have access to all fields +of your BibTeX entry. Here is an example of a details page layout:

    + +
    +
    +
    +      ---
    +---
    +<html>
    +<head></head>
    +<body>
    +  <h1>{{ page.entry.title }}</h1>
    +  <h2>{{ page.entry.author }}</h2>
    +  <p>{{ page.entry.abstract }}</p>
    +</body>
    +</html>
    +
    +    
    +
    +
    + +

    When Jekyll-Scholar generates detail pages, it also adds links to each +entry’s detail page to the generated bibliography. You can alter the +name of the link via the ‘details_link’ configuration option.

    + +

    Jekyll-Scholar also provides a Liquid tag for conveniently adding links +to individual detail pages. For example, if you would like to add a simple +link to one of the items in your bibliography on a page or in a blog post +you can use the cite_details tag to generate the link. For this to work, +you need to pass the BibTeX key of the element you want to reference to +the tag and, optionally, provide a text for the link (the default text +can be set via the ‘details_link’ configuration option).

    + +
    +
    +
    +      Duis 'aute irure dolor in reprehenderit in voluptate' velit esse cillum
    +dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
    +proident {% cite_details key --text Click Here For More Details %}.
    +
    +    
    +
    +
    + +

    Alternatively, you can use the details_link tag to get just the URL to +a details page. This can be used to link to details pages in markdown the +same way you would link to a blog post with Jekyll’s link tag.

    + +
    +
    +
    +      [See our blog post]({% link _posts/2020-01-01-research-post.md %}) 
    +or [find more details]({% details_link key %}).
    +
    +    
    +
    +
    + +

    Bibliography Filters

    + +

    By default, Jekyll-Scholar includes all entries in you main BibTeX file +when generating bibliographies. If you want to include only those entries +matching certain criteria, you can do so by adjusting the ‘query’ +configuration option. For example:

    + +
    +
    +
    +      query: "@book" #=> includes only books
    +query: "@article[year>=2003]" #=> includes only articles published 2003 or later
    +query: "@*[url]" #=> includes all entries with a url field
    +query: "@*[status!=review]" #=> includes all entries whose status field is not set to 'review'
    +query: "@book[year <= 1900 && author ^= Poe]" #=> Books published before 1900 where the author matches /Poe/
    +query: "!@book" #=> includes all entries with a type other than book
    +
    +    
    +
    +
    + +

    Please note that some of these queries require BibTeX-Ruby 2.3.0 or +later versions. You can also overwrite the configuration’s query parameter +in each bibliography tag individually as described above.

    + +

    Contributing

    + +

    The Jekyll-Scholar source code is +hosted on GitHub. +You can check out a copy of the latest code using Git:

    + +
    +
    +
    +      $ git clone https://github.com/inukshuk/jekyll-scholar.git
    +
    +    
    +
    +
    + +

    To use this lasted version instead of the one provide by RubyGems, +just add the line

    + +
    +
    +
    +      $:.unshift '/full/path/to/the/repository/lib'
    +
    +    
    +
    +
    + +

    to your _plugins/ext.rb before requiring ‘jekyll/scholar’, where +/full/path/to/the/repository is the path to your local version +of Jekyll-Scholar.

    + +

    When contributing to Jekyll-Scholar, please make sure to install +all dependencies and run the cucumber features:

    + +
    +
    +
    +      $ bundle install
    +$ rake
    +
    +    
    +
    +
    + +

    If you’ve found a bug or have a question, please open an issue on the +Jekyll-Scholar issue tracker. +Or, for extra credit, clone the Jekyll-Scholar repository, write a failing +example, fix the bug and submit a pull request.

    + +

    Additionally, if we merged at least one of your pull request you will get +write permissions to the repository if you want them.

    + +

    License

    + +

    Jekyll-Scholar is distributed under the same license as Jekyll.

    + +

    Copyright (c) 2011-2015 Sylvester Keil

    + +

    Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the ‘Software’), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

    + +

    The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

    + +

    THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/como-hacer-para-que-de-un-objeto-muestre-lo-que-yo-quiero.html b/wiki/articles/como-hacer-para-que-de-un-objeto-muestre-lo-que-yo-quiero.html new file mode 100644 index 0000000000..ad675d59e5 --- /dev/null +++ b/wiki/articles/como-hacer-para-que-de-un-objeto-muestre-lo-que-yo-quiero.html @@ -0,0 +1,418 @@ + + + + + + + + + + + Como hacer para que de un objeto muestre lo que yo quiero + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Como hacer para que de un objeto muestre lo que yo quiero +

    +
    + + + +
    +

    antes que nada, otra forma de saber si lo que me devuelve es lo que quiero

    + +

    Supongamos que tengo las clases Golondrina y Lugar, que entienden estos mensajes

    + +
      +
    • Golondrina: energia (un número), dondeEsta (un lugar), jefaDeBandada (otra golondrina)
    • +
    • Lugar: kmEnRuta (un número)
    • +
    + +

    En un workspace tengo esto

    + +

      pepita := Golondrina new. +  luciana := Golondrina new. +  buenosAires := Lugar new. +  pepita initialize. +  luciana initialize. +  buenosAires initialize. +  buenosAires kmEnRuta: 10. +  pepita jefaDeBandada: luciana. "le digo a pepita que la jefa de su bandada es luciana" +  pepita ubicacionInicial: buenosAires.   "después de esto, pepita está en buenos aires"

    + +

    Si después de todo esto en el workspace pongo

    + +

       pepita energia

    + +

    y le doy display it, me va a mostrar un número, p.ej. 0. Ahora, si pongo

    + +

       pepita jefaDeBandada

    + +

    y le doy display it, no me va a mostrar “luciana” que es tal vez lo que esperaba, sino “a Golondrina”. Parecido si pruebo con

    + +

       pepita dondeEsta

    + +

    me va a decir “a Lugar”.

    + +

    Si tengo 5 golondrinas en mi workspace, ¿cómo sé que la que me devuelve cuando le pido la jefa de bandada a pepita es luciana y no otra? “luciana” es el nombre de la variable que apunta a luciana dentro del workspace, entonces dentro del workspace puedo usar ese nombre. Sabiendo esto, una fácil es preguntar si lo que me devuelve pepita jefaDeBandada es luciana, o sea

    + +

       pepita jefaDeBandada = luciana

    + +

    ahora las respuestas van a ser true o false.

    + +

    ahora sí, el misterio de “a Golondrina”

    + +

    Ponele que estás pensando “todo bien, pero lo que quiero es que no me ponga ‘a Golondrina’”. Adelante.

    + +

    Empecemos por entender por qué pone “a Golondrina”.

    + +

    Ya vimos que los objetos no tienen “nombre propio”, los que tienen nombre son las variables que hacen referencia al objeto. luciana es la variable del workspace que apunta a una golondrina, la golondrina no tiene nombre propio.

    + +

    Entonces, cuando pinto una expresión y le doy “display it”, ¿qué me muestra? Me muestra un String que representa al objeto resultado de la expresión. Para los objetos básicos (números, String, booleanos), ese String es lo que uno espera. Para las instancias de las clases que creamos nosotros, es en principio el nombre de la clase antecedido de “a “ (o “an “ si el nombre de la clase empieza en vocal). Por eso “a Golondrina”.

    + +

    Si entendimos esto, la pregunta que sigue es ¿puedo hacer que el String que representa a (p.ej.) las golondrinas no sea “a Golondrina” sino otra cosa que yo quiera.

    + +

    Sí, y no es muy difícil.

    + +

    printOn:

    + +

    Lo que hay que hacer es definir el método

    + +

       printOn:

    + +

    en la clase cuyas instancias queremos que se muestren distinto (en el ejemplo, Golondrina y Lugar).

    + +

    Lo que viene como parámetro es un Stream, que es una tira de caracteres. En el método tenés que agregar el String que vos quieras a la tira. Todos los objetos son polimórficos respecto del printOn:, para las clases que no tienen una definición explícita, Smalltalk provee la que muestra el nombre de la clase.

    + +

    El “display it” lo que hace es: crear un Stream, pedirle al resultado de la expresión printOn: sobre ese Stream, tomar el String generado, mostrar eso.

    + +

    Los Stream entienden estos mensajes:

    + +
      +
    • nextPutAll: unString , agrega unString a la tira
    • +
    • cr , agrega un salto de línea a la tira
    • +
    + +

    Tengamos también en cuenta que los String entienden el mensaje coma (,) que concatena, probar p.ej.

    + +

      'hola ', 'mundo'

    + +

    Más sobre Strings en el apunte sobre objetos básicos en www.pdep.com.ar .

    + +

    Ya vimos que los objetos básicos se muestran bien, y ahora sabemos que eso es porque al decirle printOn: devuelven un String feliz. P.ej. el 42 agrega el String “42”, por eso es que cuando el resultado de una operación es 42 y le pido “display it” de esa operación, me muestra “42” y no “a Number”. Esto lo podemos usar, si dentro de lo que quiero mostrar hay p.ej. un número, entonces al número le puedo decir printOn: sobre el mismo Stream que me pasaron a mí.

    + +

    Hagamos que los lugares y golondrinas se muestren bien

    + +

       #Lugar +   printOn: unStream +       unStream nextPutAll: 'lugar en km '. +       self kmEnRuta printOn: unStream             

    + +

    la segunda línea de código agrega el String correspondiente al número en el mismo Stream que le llegó al lugar, entonces el resultado va a ser p.ej. “lugar en km 10”.

    + +

       #Golondrina +   printOn: unStream +       unStream nextPutAll: 'golondrina con energía '. +       self energia printOn: unStream. +       unStream nextPutAll: ' y que está en ('. +       self dondeEsta printOn: unStream. +       unStream nextPutAll: ')'.

    + +

    acá usé el mismo truco para la energía (un número) y para el lugar, para el que va a usar el printOn: de lugar que definimos recién. Entonces el resultado va a ser “golondrina con energía 0 y que está en (lugar en km 10)”.

    + +

    ok, pero quiero que me diga “pepita”

    + +

    Bueno, para eso el objeto tiene que conocer al String ‘pepita’. P.ej. que las golondrinas tengan nombre. ¿Cómo? Bueno, eso ya lo deberían poder hacer ustedes ;-).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/como-hacer-predicados-de-orden-superior.html b/wiki/articles/como-hacer-predicados-de-orden-superior.html new file mode 100644 index 0000000000..934604ed54 --- /dev/null +++ b/wiki/articles/como-hacer-predicados-de-orden-superior.html @@ -0,0 +1,469 @@ + + + + + + + + + + + Como hacer predicados de orden superior + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Como hacer predicados de orden superior +

    +
    + + + +
    +

    Recordemos los predicados de orden superior que vimos hasta el momento, esos “predicados que relacionan predicados”:

    + +
      +
    • not/1
    • +
    • findall/3
    • +
    • forall/2
    • +
    + +

    ¿Eso es todo lo que hay? No, por supuesto que no. Existen muchos otros predicados de orden superior “pre-construidos” (built-in), pero esta base nos alcanza para lo que queremos ver en la materia. Pero lo más interesante es que podemos construir nuestros propios predicados de orden superior, sin embargo vamos a ver que no es tan natural como sí era en Haskell.

    + +

    call / 1

    + +

    El predicado call/1 nos permite evaluar un predicado pasado por parámetro. Retomando uno de nuestros primeros ejemplos, veamos cómo se usaría:

    + +

    ?- call(padre(Padre, Hijo)). +Padre = homero +Hijo = bart ; +...

    + +

    Pero eso no aporta mucho respecto de hacerlo en forma directa:

    + +

    ?- padre(Padre, Hijo). +Padre = homero +Hijo = bart ; +...

    + +

    Se supone que sólo tiene sentido usar esto si no sabemos qué consulta es la que nos van a pasar por parámetro y usamos el call/1 para definir algo más genérico. Veamos otra variante, entonces, que puede resultarnos más interesante y útil para lo que sí podemos llegar a usar.

    + +

    call / _

    + +

    El predicado call/_ también nos permite evaluar un predicado pasado por parámetro, pero separando los parámetros que el mismo recibe:

    + +

    ?- call(padre, Padre, Hijo). +Padre = homero +Hijo = bart ; +...

    + +

    O también:

    + +

    ?- call(padre(homero), Hijo). +Hijo = bart ; +...

    + +

    Momento, momento… entonces, ¿cuál es la aridad de call/_? El predicado call/_ no tiene definida una aridad fija. Puede tener desde 1 (la versión que vimos antes) hasta N + 1, siendo N la aridad del predicado que se recibe como primer parámetro.

    + +

    Usando este predicado podemos hacer cosas equivalentes (¡no iguales!) a las que hacíamos con orden superior en Haskell. Juguemos un poco con esto: implementemos map y filter.

    + +

    Creando nuestros propios predicados de orden superior

    + +

    el viejo y querido filter

    + +

    La cuestión de los parámetros es igual a la anterior: vamos a necesitar uno más que lo que tenía filter en Haskell para unificar la lista resultante. Hagamos también dos versiones.

    + +

    Versión recursiva:

    + +

    filterRecursivo( _ , [] , [] ). +filterRecursivo(Pred, [X | Xs], [X | Ys]):- +  call(Pred, X), +  filterRecursivo(Pred, Xs, Ys). +filterRecursivo(Pred, [X | Xs], Ys):- +  not(call(Pred, X)), +  filterRecursivo(Pred, Xs, Ys).

    + +

    Versión no recursiva:

    + +

    filterNoRecursivo(Pred, ListaOrigen, ListaResultante):- +  findall(X, (member(X, ListaOrigen), call(Pred, X)), ListaResultante).

    + +

    Ejemplos de consulta:

    + +

    ?- filterRecursivo(padre(homero), [herbert, lisa, maggie, homero, bart], ListaFiltrada). +ListaFiltrada = [lisa, maggie, bart] ; +No +?- filterNoRecursivo(padre(homero), [herbert, lisa, maggie, homero, bart], ListaFiltrada). +ListaFiltrada = [lisa, maggie, bart] ; +No

    + +

    Buenísimo :D Este predicado también existe como built-in y, como el título lo dice, es include/3.

    + +

    el viejo y querido map

    + +

    Empecemos por lo básico… ¿cuántos parámetros tenía la función map?

    + +

    > map f lista

    + +

    Tenía dos parámetros, una función de transformación “f” y una lista, y la función era aplicable a cada elemento de la lista.

    + +

    Entonces, ¿cuántos argumentos va a tener nuestra relación maplist? Vamos a tener el predicado de transformación y la lista, por supuesto. Pero también necesitamos un argumento más para unificarlo con la lista resultante del mapeo. Tenemos también que considerar las cosas que relaciona el predicado: un elemento de la lista original con uno de la lista resultante.

    + +

    ?- map(Predicado, ListaOriginal, ListaResultante).

    + +

    Ejemplo de uso:

    + +

    ?- map(padre, [homero,abe], Hijos). +Hijos = [[bart,lisa,maggie],[homero,herbert]]

    + +

    Ok, pensemos cómo lo podríamos implementar para que haga lo que queremos?

    + +

    Versión 1 con recursividad

    + +

    mapRecursivo( _ , [] , [] ). +mapRecursivo(Pred, [X|Xs], [Y|Ys]):- +  call(Pred, X, Y), +  mapRecursivo(Pred, Xs, Ys).

    + +

    Ejemplos de consulta:

    + +

    ?- mapRecursivo(padre, [homero,abe], Hijos). +Hijos= [bart, homero] ; +Hijos= [bart, herbert] ; +Hijos= [lisa, homero] ; +Hijos= [lisa, herbert] ; +Hijos= [maggie, homero] ; +Hijos= [maggie, herbert] ; +No

    + +

    Ok… esto no hace lo que queremos, vemos que vamos a tener múltiples respuestas donde para cada padre me mappea con un único hijo de ese padre. Pensándolo desde un punto de vista genérico, más allá del dominio particular, nuestra primer implementación nos da N respuestas con todas las combinaciones posibles de mapeo, pero siempre con mapeos 1 a 1 para cada elemento de la lista original. Qué más se nos ocurre?

    + +

    Versión 2 con findall También podríamos hacer una versión no recursiva:

    + +

    mapNoRecursivo(Pred, ListaOriginal, ListaResultante):- +   findall(Y, (member(X, ListaOriginal), call(Pred, X, Y)), ListaResultante).

    + +

    Ejemplos de consulta:

    + +

    ?- mapNoRecursivo(padre, [homero,abe], Hijos). +Hijos = [bart, lisa, maggie, homero, herbert] ; +No

    + +

    Para nuestra implementación no recursiva la respuesta es única, pero están en la misma lista los hijos de todos y según nuestro ejemplo de uso esperado que dijimos al principio queríamos que nos de una lista de listas, sino no podemos distinguir los que son hijos de homero respecto a los de abe.

    + +

    Las dos implementaciones que realizamos sin embargo funcionarían correctamente con relaciones que cumplan con unicidad (con lo cual estaríamos más cerca del mundo funcional, no siempre queremos esto, depende del problema). Si modeláramos la relación hijosDe/2 como:

    + +

    hijosDe(Padre,Hijos):- findall(Hijo, padre(Padre,Hijo), Hijos).

    + +

    Podríamos hacer la siguiente consulta

    + +

    ?- mapNoRecursivo(hijosDe, [homero,abe], Hijos). +Hijos = [[bart,lisa,maggie],[homero,herbert]]

    + +

    Y el resultado sería idéntico al de nuestro mapRecursivo.

    + +

    Y cuál es el que está bien? La respuesta es depende. Si buscamos múltiples respuestas con relaciones 1 a 1 vamos a querer la primera, si buscamos una única respuesta que englobe todas las respuestas posibles vamos a querer la segunda, y si queremos que sea 1 a 1 con una única respuesta tenemos que asegurarnos de que nuestro dominio esté modelado de forma acorde, incluso podríamos tener una tercer versión como esta:

    + +

    Versión 3 con recursividad y findall

    + +

    mapListaDeListas( _ , [] , [] ). +mapListaDeListas(Pred, [X|Xs], [Y|Ys]):- +  findall(Z,call(Pred, X, Z),Y), +  mapListaDeListas(Pred, Xs, Ys).

    + +

    Esta consulta va a hacer lo que queríamos originalmente, pero siempre nos va a dar una lista de listas y capaz no queremos eso…

    + +

    ?- mapListaDeListas(padre, [homero,abe], Hijos). +Hijos = [[bart,lisa,maggie],[homero,herbert]]

    + +

    Ya que estamos en lógico, pensemos qué otras consultas podríamos querer hacer:

    + +

    ?- mapRecursivo(padre, Padres, [bart, lisa, maggie]). +Padres = [homero, homero, homero] ; +No

    + +

    Nuestra primer versión recursiva es inversible para el segundo o el tercer argumento (aunque no ambos simultáneamente). Si probamos lo mismo con nuestra versión no recursiva, nos vamos a encontrar con un problema ya que en la implementación estamos usando member/2 con la primera lista, y member/2 no es inversible para la lista.

    + +

    Lógicamente ninguna versión será inversible respecto al primer argumento, ya que necesita saber qué predicado quiere consultar en el call.

    + +

    Bueno, la versión built-in de map en SWI-Prolog es maplist/3, y se comporta como nuestra versión recursiva.

    + +

    ¿Cómo seguimos?

    + +

    Otro predicado de orden superior muy útil es mejorSegun/3 que relaciona un predicado de aridad 2 a invocar, una lista y al valor que maximiza el segundo argumento del predicado en cuestión. Se animan a resolverlo?

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/composicion--oop-.html b/wiki/articles/composicion--oop-.html new file mode 100644 index 0000000000..ec1eac2484 --- /dev/null +++ b/wiki/articles/composicion--oop-.html @@ -0,0 +1,553 @@ + + + + + + + + + + + Composicion oop + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Composicion oop +

    +
    + + + +
    +

    Supongamos que queremos modelar el comportamiento de personas a la hora de pagar la cuenta después de una comida en un restaurant. Los clientes pagan lo que consumen más la propina, que depende de su humor. Sabemos que la gente feliz deja de propina 25% de lo que salió la comida, la gente enojada no deja nada y los que están de un humor indiferente dejan lo que tienen en el bolsillo.

    + +

    Queremos que un cliente nos pueda decir cuánto paga en total (propina + lo que consumió) dado el importe de la comida consumida, y además debe ser posible para una persona cambiar de humor a lo largo de la ejecución del programa.

    + +

    Sería posible resolver toda esta lógica (y la que esté por venir más adelante) con muchos ifs en el cliente, pero es posible modelarlo de otra forma: los diferentes humores del cliente podrían ser otros objetos separados que le ayuden a saber cuánta propina poner, y por su puesto ser polimórficos para que el cliente pueda delegar en ellos esta funcionalidad sin importar cuál sea su humor actual (objeto al cual referencia con algún atributo propio, como ser humor).

    + +

    Wollok

    + +
    class Cliente {
    +  var property humor
    +  method cuantoPaga(importeTotal){
    +    return importeTotal + self.cuantoDePropina(importeTotal)
    +  }
    +  method cuantoDePropina(importeTotal){ 
    +    return humor.cuantoDePropina(importeTotal)
    +  }
    +}
    +  
    +class Feliz {
    +  method cuantoDePropina(importeTotal){
    +    return importeTotal * 1.25
    +  }
    +
    +class Enojado {
    +  method cuantoDePropina(importeTotal){
    +    return 0
    +  }
    +}
    +
    +class Indiferente {
    +  var property plataDelBolsillo
    +  method cuantoDePropina(importeTotal)
    +    return plataDelBolsillo
    +  }
    +}
    +
    + +

    Nota: en este ejemplo se ubicó la variable plataDelBolsillo en la estrategia Indiferente. Esto implica que cada vez que el cliente cambie de humor a indiferente, hay que indicarle cuánta plata en el bolsillo tiene.

    + +

    Otra opción podría haber sido poner la plataDelBolsillo en el cliente y para que la estrategia Indiferente resuelva cuánto tiene que devolver al recibir el mensaje cuantoDePropina hay dos opciones:

    + +
      +
    • Que la instancia del objeto Indiferente conozca al Cliente y le pida su plataDelBolsillo
    • +
    • Que el cliente se pase por parámetro al pedirle a la estrategia cuánta propina pone, modificando el método para recibir dos parámetros, por ejemplo:
    • +
    + +

    Wollok

    + +
    class Cliente {
    +  method cuantoDePropina(importeTotal){
    +    return humor.cuantoDePropinaPara(importeTotal,self)
    +  }
    +}
    +
    + +

    Ante la necesidad de poder cambiar el humor de la persona, separamos a la Persona (que intuitivamente iba a ser un concepto entero abarcando a su estado de humor) de su Humor en un concepto aparte. Los objetos Humor deben ser polimórficos para la persona, ya que debo poder intercambiar los distintos humores y la persona debería hablarle de la misma forma a cualquiera.

    + +

    Entonces en vez de tener un objeto que resuelve todo el problema tenemos un objeto que conoce a otros objetos polimórficos para resolver el problema mediante la colaboración. Con esta solución, el flujo del programa ya no se encuentra definido por los ifs y objetos básicos sino por la configuración del cliente y el uso de polimorfismo.

    + +

    Es importante notar que no sería válido modelar una solución a este problema basada en herencia teniendo personas felices, indiferentes y enojadas, ya que una vez que la persona es instanciada como feliz no es posible cambiarla a indiferente o enojada, ya que implicaría cambiar su clase que no se puede hacer.

    + +

    Entonces, la composición en objetos es simplemente una relación de conocimiento entre dos objetos (por ejemplo, el cliente conoce a su humor) donde el objeto conocido puede cambiarse por otro que sea polimórfico para el que los conoce.

    + +

    Otro ejemplo podría ser el de las colecciones con un algoritmo de ordenamiento elegido por el usuario (SortedCollection en Smalltalk), donde la colección delega en otro objeto que modela el algoritmo de ordenamiento a usar sobre sus elementos.

    + +

    Cambiando herencia por composición

    + +

    El uso de composición en ocasiones es una solución muy elegante para problemas aparejados por el concepto de Herencia, que pueden verse en el siguiente ejemplo tomado de un final de Paradigmas de Programación:

    + +
    +

    El siguiente texto representa parte del relevamiento realizado en una cadena de venta de electrodomésticos: “Los vendedores pueden ser especialistas o de salón. Los especialistas atienden detrás de mostrador y cobran un premio de 100 pesos por cada venta. Los vendedores de salón cobran un premio que se indica para cada vendedor.”

    + +

    Avanzando en el relevamiento, nos dicen lo siguiente:

    + +

    “Para motivar las ventas en el equipo, decidimos incorporar un cambio: categorías senior y junior. Un vendedor senior tendrá a cargo a un junior. Un vendedor senior recibe como parte del premio un adicional correspondiente al 3% de las ventas realizadas por la persona que tiene a cargo. Un Junior tiene un porcentaje de descuento en su premio. Por otra parte, si un vendedor junior hace bien las cosas, con el tiempo puede pasar a ser senior”

    +
    + +

    La codificación propuesta en el enunciado es:

    + +

    Wollok

    + +
    class VendedorEspecialista {
    +  const ventas = []
    +  method premio(){
    +    return 100 * ventas.length()
    +  }
    +}
    +
    +class VendedorSalon {
    +  const ventas = []
    +  var premio
    +  method premio(){
    +    return premio
    +  }
    +}
    +
    +class VendedorSalonSenior inherits VendedorSalon {
    +  var junior
    +  method premio(){
    +    return super() + self.adicionalJunior()
    +  }
    +  method adicionalJunior(){
    +    return junior.totalVentas() * 0.03
    +  }
    +}
    +
    +class VendedorSalonJunior inherits VendedorSalon {
    +  var descuento
    +  method totalVentas(){
    +    return ventas.sum({ venta => venta.monto() })
    +  }
    +  method premio(){
    +    return super() * (1 - self.descuento())
    +  }
    +}
    +
    +class VendedorEspecialistaSenior inherits VendedorEspecialista {
    +  var junior
    +  method premio(){
    +    return super() + self.adicionalJunior()
    +  }
    +  method adicionalJunior(){
    +    return junior.totalVentas() * 0.03
    +  }
    +}
    +
    +class VendedorEspecialistaJunior inherits VendedorEspecialista {
    +  var descuento
    +  method totalVentas(){
    +    return ventas.sum({ venta => venta.monto() })
    +  }
    +  method premio(){
    +    return super() * (1 - self.descuento())
    +  }
    +}
    +
    + +

    La solución propuesta tiene problemas que surgen por el mal uso de herencia. Los que podemos destacar son:

    + +
      +
    • Repetición de código: La forma de subclasificar a los vendedores tanto por tipo de vendedor (Salón o Especialista) como por categoría (Senior o Junior) hace que tengamos código repetido entre las hojas del árbol de herencia. Esto tiene problemas, sobre todo si el sistema sigue creciendo de esta forma, ya que la repetición de código es exponencial y realizar un cambio en la lógica del premio de los juniors por ejemplo se propagaría para todos los tipos de vendedores habidos y por haber (tiene problemas de extensibilidad).
    • +
    • Problemas con la identidad de los objetos: El enunciado indica que un junior puede volverse senior con el tiempo, pero el modelo que tenemos no soporta este tipo de cambio en tiempo de ejecución. Un objeto de la clase VendedorSalonJunior no puede cambiar de clase a VendedorSalonSenior, su clase es algo que se mantiene durante toda la vida del objeto. Si tratamos de emular el cambio de clase creando un nuevo objeto y copiando los valores de sus atributos según corresponda lograremos tener el comportamiento de senior pero ya no será el mismo objeto para el sistema. En OOP una de las características de un objeto es su identidad, la cual estaríamos perdiendo si tomamos esa decisión y el problema asociado a este cambio es que todos los objetos que tengan una referencia a nuestro vendedor promovido deberán enterarse de este cambio (y seguramente no lo hagan) para referenciar al nuevo objeto que lo reemplaza. La consecuencia de esto es o bien una complejidad espantosa para mantener las referencias o un sistema inconsistente.
    • +
    + +

    ¿Cómo se soluciona este problema? Si cambiamos el modelo para que la categoría (Junior o Senior) sea un objeto aparte que el vendedor conozca y delegamos en este objeto todo aquello que corresponda a ser senior o junior solucionamos ambos problemas a la vez, ya que el valor de las referencias sí puede ser cambiado en tiempo de ejecución, es sólo settear un atributo. Veamos cómo queda la nueva solución:

    + +

    Wollok

    + +
    class Vendedor {
    +  const ventas = []
    +  var categoria
    +  
    +  method premio(){
    +    return categoria.premioPara(self)
    +  }
    +  method totalVentas(){
    +    return ventas.sum({ venta => venta.monto() })
    +  }
    +}
    +
    +class VendedorEspecialista inherits Vendedor {
    +  method premioBase(){
    +    return 100 * ventas.length()
    +  }
    +}
    +
    +class VendedorSalon inherits Vendedor {
    +  var premioBase
    +  method premioBase(){
    +    return premioBase
    +  }
    +}
    +
    +class Senior {
    +  var junior
    +  method premioPara(unVendedor){
    +    return unVendedor.premioBase() + self.adicionalJuniorPara(unVendedor)
    +  }
    +  method adicionalJuniorPara(unVendedor){
    +    return junior.totalVentas() * 0.03.
    +  }
    +}
    +
    +class Junior {
    +  var descuento
    +  method premioPara(unVendedor){
    +    return unVendedor.premioBase() * (1 - self.descuento())
    +  }
    +}
    +
    + +

    Disclaimer: el método totalVentas se termina definiendo en la clase Vendedor porque tenía sentido para todos en este dominio, no sólo para los juniors. Para que fuera totalmente análoga podríamos tenerlo definido en Junior y delegar en la categoría, pero siendo que no es inválido que los vendedores lo definan, era más sencillo resolverlo de esta forma. En caso de dudas de dominio, siempre vale preguntar.

    + +

    Como se puede ver en el diagrama de clases de la solución con composición, para crear un vendedor ya no alcanza sólo con elegir la clase del tipo de vendedor que queremos e instanciarla, sino que tenemos que instanciar dos objetos (al vendedor que queramos y su categoría) y hacer que el vendedor conozca a su categoría, lo cual agrega una complejidad extra para la creación de nuestros objetos. Si más adelante quisiéramos que un vendedor también pueda pasar de ser vendedor de salón a especialista y viceversa, podría plantearse una solución en la cual el vendedor conozca a su categoría y también a su modo de venta, complicando más el armado de un vendedor a cambio una mayor flexibilidad del modelo.

    + +

    A modo de resumen rápido:

    + +

    Herencia

    + +
      +
    • Estática (no puedo cambiar la clase de un objeto en run-time, si creo otro objeto se pierde la identidad lo cual trae problemas)
    • +
    • Menos objetos -> Menos complejidad
    • +
    • Es una relación entre clases! Es mucho más fuerte que la relación entre instancias planteada en composición. La herencia implica no sólo heredar código sino conceptos.
    • +
    + +

    Composición

    + +
      +
    • Dinámico (la implementación se puede cambiar en run-time, ya que se basa sólo en un atributo que se puede settear en cualquier momento con otro objeto que sea polimórfico)
    • +
    • Aumenta la cantidad de objetos -> Mayor complejidad (Es más complicado entender el todo y hay que configurar adecuadamente las relaciones entre los objetos)
    • +
    • Se reparten mejor las responsabilidades en objetos más chicos
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/composicion.html b/wiki/articles/composicion.html new file mode 100644 index 0000000000..55112935a6 --- /dev/null +++ b/wiki/articles/composicion.html @@ -0,0 +1,521 @@ + + + + + + + + + + + Composicion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Composicion +

    +
    + + + +
    +

    Qué es composición?

    + +

    ¿Qué queremos decir con ‘Componer’?
    +Lo mismo que con composición de funciones en matemática.

    + +

    fog(x) es lo mismo que f(g(x))

    + +

    Es decir que lo que devuelve g, hay que aplicárselo a f. A tener en cuenta, tanto f como g tienen que ser funciones, no podemos componer una función con un 2, o un 2 con una lista.

    + +
    +

    Sólo podemos componer funciones

    +
    + +

    Para componer dos funciones en Haskell, por ejemplo f y g, se hace así

    + +
    f . g
    +
    + +

    eso arma una nueeeva función, resultado de componer f con g.

    + +

    Ejemplo

    + +
    even . succ
    +
    + +

    Esta formada por la composición de even que recibe un numero y devuelve un Bool que indica si es par o no, y succ que recibe un numero y devuelve el siguiente. Esa composición te devuelve una nueva función que recibe un número y te devuelve el resultado de primero sumarle uno y luego ver si es par:

    + +
    (not . even) 2       (espero se entiendan mis flechitas xD)
    +  ^  |  ^    |
    +  |__|  |____|
    +
    + +

    Fijate que el 2 se aplica a la función de la derecha y el resultado de eso se aplica a la función de la izquierda. Y ese sería el resultado final de la función.

    + +

    Tanto lo de la izquierda como lo de la derecha del punto, tienen que ser funciones que reciban 1 parámetro (al menos en paradigmas, lo otro es más complejo). Y a su vez, el tipo que retorna la función de la derecha, tiene que ser el mismo que el tipo que espera recibir la función de la izquierda. En este caso, even es una función que recibe un Integral (ver typeclasses) y retorna un Bool.

    + +
    even :: Integral a => a -> Bool
    +
    + +

    y not recibe un Bool y retorna otro.

    + +
    not :: Bool -> Bool
    +
    + +

    Conviene prestar atención a lo siguiente: lo que devuelve even, coincide con lo que recibe not. Eso hace posible la composición!

    + +

    Preguntas Frecuentes

    + +

    ¿Es necesesario que esten los puntos para que sea composicion?

    + +

    Porque para mí está implícito que hay composición, si por ejemplo en lugar de:

    + +
    impar = not . even
    +
    + +

    pongo

    + +
    impar = not even
    +
    + +

    Sí, es necesario. En el segundo ejemplo estas aplicando even a not, y not espera un Bool, no una función y por ende, ni compila por error de tipos.

    + +

    En cambio, cuando hacés

    + +
    not . even
    +
    + +

    estás armando una nueva función que recibe un número, ve si es par y después lo niega. La forma de armar la función que querés, según el segundo ejemplo sería:

    + +
    not (even 3)
    +
    + +

    Y en el segundo se aplicaría así:

    + +
    (not . even) 3
    +
    + +

    Cuándo usar composición

    + +

    ¿Cuál es la diferencia entre estas dos definiciones?

    + +
    impar n = not (even n)
    +impar = not ◦ even
    +
    + +

    En un primer nivel de análisis, ambas definiciones son equivalentes.

    + +

    Sin embargo, si analizamos solamente las expresiones a la derecha del igual encontramos que

    + +
    not (even n)
    +
    + +

    y

    + +
    not . even
    +
    + +

    son distintas: la primera denota un valor booleano (True o False) mientras que la segunda denota una función.

    + +

    Esta segunda expresión es más poderosa en cuanto a que nos permite hacer más cosas que la primera, ya que la construcción de la función independiente de su aplicación sirve, por ejemplo, para trabajar con funciones de orden superior.

    + +

    En cuanto a la definición de función, no tiene grandes ventajas sobre salvo que nos ayuda a entrenarnos en el uso de la composición, que después podemos utilizar para otras cosas. Sin embargo, una de las virtudes asociadas si se reemplazan muchas aplicaciones anidadas por composición de funciones podría implicar un código más limpio, porque la sintaxis de Haskell está diseñada de modo que eso suceda.

    + +

    Errores comunes

    + +

    Ejemplo

    + +

    Supongamos una lista de alumnos de los cuales se sabe su nombre y su nota. Queremos obtener los nombres de los alumnos aprobados.

    + +

    Podemos suponer además la existencia de las funciones:

    + +
    nombres :: [Alumno] -> [String]
    +aprobados :: [Alumno] -> [Alumno]
    +
    + +

    Un error que veo con frecuencia es hacer:

    + +
    nombreDeAprobados alumnos = nombres . aprobados alumnos
    +
    + +

    La composición es una operación entre funciones esto quiere decir que a ambos lados del “.” debe haber una función. ¿Qué hay a cada lado del “.” en este caso:

    + +
      +
    • +

      nombres , no hay problema: es una función (de listas de alumnos/tuplas en listas de nombres);

      +
    • +
    • +

      aprobados alumnos … sí hay problema! No es una función, es una lista de alumnos.

      +
    • +
    + +

    Diciéndolo “en fácil”: debo componer funciones, no vale componer valores. Si yo a una función le aplico todos los parámetros deja de ser una función y pasa a ser un valor “simple”. En este caso, aprobados es una función, mientras que aprobados alumnos es un valor, y como tal no se puede componer. Tal vez sea interesante ver el efecto de la currificación en Haskell.

    + +

    Correcciones posibles

    + +

    Sin composición

    + +
    aprobados alumnos = nombres (aprobados alumnos)
    +
    + +

    Es decir uso aplicación en lugar de composición (ojo, esto funciona pero si en estamos en un parcial y se desea evaluar que el alumno sepa composición… ahí no están usando composición entonces puede no ser suficiente como solución al ejercicio).

    + +

    Con composición

    + +
    nombreDeAprobados = nombres . aprobados
    +
    + +

    Claramente son funciones las dos expresiones a ambos lados del “.”. (Notese que a la derecha del “=” también hay un parámetro menos.)

    + +

    Pueden encontrar otro ejemplo sobre esta clase de errores en Errores con composición y aplicación parcial

    + +

    Composición vs. Aplicación

    + +

    Para terminar de entenderlo recuerden la matemática, ¿es lo mismo que ? Claramente si g es una función yo no puedo hacer . Por otro lado, si en lugar de una función g tuviera un valor real x, entonces puedo hacer pero no .

    + +

    Algunos detalles técnicos

    + +

    Si bien en general intentamos concentrarnos en los conceptos y no prestar tanta atención al conocimiento en sí del lenguaje; para poder expresar correctamente una composición en Haskell es necesario comprender correctamente algunos detalles de la sintaxis del Haskell:

    + +
      +
    1. +

      Si pongo un “.” es composición, sino es aplicación. Los dos conceptos son bien distintos y es muy importante comprender la diferencia; por lo tanto es necesario ser bien explícito sobre cuándo se esta queriendo utilizar uno u otro. En criollo, se tiene que notar dónde hay un punto y dónde no.

      +
    2. +
    3. +

      El operador de composición tiene poca precedencia. (Ver Aplicación Parcial) Por lo tanto la expresión not . even 3 debe leerse como not . (even 3) (y por lo tanto es incorrecta). Una alternativa posible es alterar la precedencia explícitamente usando paréntesis, por ejemplo (not.even) 3; donde primero se componen las funciones, eso produce una nueva función, y a esa nueva función le aplico el 3 como parámetro.

      +
    4. +
    + +

    Para más información puede leer: Precedencia de los operadores más comunes en Haskell y Cuándo usar paréntesis

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/comunicacion.html b/wiki/articles/comunicacion.html new file mode 100644 index 0000000000..cf94922b55 --- /dev/null +++ b/wiki/articles/comunicacion.html @@ -0,0 +1,361 @@ + + + + + + + + + + + Comunicacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Comunicacion +

    +
    + + + +
    +

    Cuando construimos modelos mentales sobre los problema que queremos resolver, ya sea como parte del proceso de análisis, diseño, etc, normalmente queremos luego transmitirlos Esto ocurre porque:

    + +
      +
    • Queremos compartirlo con otros: para explicar nuestro modelo construido e intercambiar opiniones sobre el mismo
    • +
    • Queremos construir documentación: una referencia persistente sobre lo que hemos pensado, la cual será una fuente de consulta para otros o nosotros mismos en un futuro mas o menos lejano, cuando ya hayamos olvidado la información que recopilamos y las decisiones que tomamos.
    • +
    + +

    Formas de comunicación

    + +

    Tenemos varias formas de comunicar estas ideas, por ejemplo

    + +
      +
    • un texto en prosa
    • +
    • una especificación de CU en la etapa de análisis
    • +
    • una porción de código o pseudocódigo en la etapa de diseño
    • +
    • un caso de prueba
    • +
    + +

    son formas validas de comunicarlas. Otra forma útil son los diagramas, que normalmente son menos detallados pero transmiten las ideas principales de nuestra realidad modelada más rápidamente.

    + +

    Los diagramas empleados para comunicar varían en función de su objetivo; probablemente necesite diagramas diferentes para comunicar ideas diferentes. No es lo mismo mostrar la disposición de los servidores en un sistema distribuido que la disposición de los componentes visuales en una interfaz gráfica.

    + +

    Por otro lado, el tipo de diagrama que construyamos depende del paradigma en el que estoy modelando: la naturaleza de los componentes y su responsabilidades es diferente, por ejemplo, en el paradigma procedural y en el orientado a objetos.

    + +

    Finalmente, muchas veces emplearemos distintos diagramas que modelan de forma complementaria aspectos diferentes de la misma cosa.

    + +

    UML

    + +

    UML significa Unified Modeling Language (Lenguaje Unificado de Modelado) y basicamente son un conjunto de especificaciones para hacer muchos (realmente muchos) diagramas de distintos tipos. Es un lenguaje que nos permite comunicar ideas de diseño desde diferentes puntos de vista, y con distinto enfoques. UML se compone de una serie de diagramas, donde cada uno tiene un objetivo en cuanto a lo que quiere comunicar.

    + +

    Acá hay alguno de los diagramas de UML

    + +

    Una ventaja no menor de UML frente a otros como por ejemplo LePUS es su amplia difusión, lo que significa que son conocidos por una gran parte de los perfiles, y que además, existen muchos aplicativos para su construcción.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/concepto-de-funcion.html b/wiki/articles/concepto-de-funcion.html new file mode 100644 index 0000000000..bb3f46d35a --- /dev/null +++ b/wiki/articles/concepto-de-funcion.html @@ -0,0 +1,397 @@ + + + + + + + + + + + Concepto de funcion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Concepto de funcion +

    +
    + + + +
    +

    Como su nombre lo indica, la función es el concepto fundamental del paradigma funcional: mientras que, por ejemplo, en el paradigma de objetos, los problemas se resuelven en términos de envío de mensajes entre objetos, en funcional los programas se estructurarán en torno a aplicación de funciones sobre valores. La función, es así, pues, la computación característica del paradigma.

    + +

    Enfoques

    + +

    Función como caja negra

    + +

    Una forma simple de pensar una función es como una máquina con una salida y al menos una entrada, capaz de producir un resultado. Decimos que se trata de una caja negra, porque para aquel que la use no tiene acceso al interior de la misma, sino tan solo a sus entradas y salida. Esto nos lleva a que las funciones pueden ser combinadas fácilmente, de diversas formas, tan solo conociendo el tipo de entradas y salidas que posee.

    + +

    Función como transformación matemática

    + +

    Las funciones, sin embargo, no son simples cajas negras, que podrían, por ejemplo, tener memoria de sus entradas anteriores, sino que son transformaciones matemáticas que presentan transparencia referencial.

    + +

    En particular, las funciones son relaciones que presentan las siguientes características:

    + +
      +
    • para toda entrada aceptable (su dominio), existe un único resultado (imagen), lo cual se conoce como unicidad.
    • +
    • para toda entrada del dominio, existe un resultado, lo que se conoce como existencia.
    • +
    + +

    Función desde un punto de vista procedural

    + +

    Al llevar los conceptos de función matemática al mundo computacional, la transparencia referencial implica que las funciones, comparadas contra los procedimientos imperativos, no tienen efecto, su aplicación no afecta al contexto, o, cuando menos, no es visible para el observador que evalua la expresión.

    + +

    Si bien no tiene sentido hablar de mutabilidad en el contexto matemático, dado que solo se manejan valores y no referencias (al menos, en un enfoque simplista), la transparencia referencial en los programas construidos en el paradigma funcional tiene dos consecuencias mas o menos evidentes:

    + +
      +
    • Las funciones no pueden mutar sus argumentos ni otras variables, locales o globales, ni directa ni indirectamente. Esto se garantiza al eliminar la asignación destructiva del lenguaje. (podemos decir que las variables no varían)
    • +
    • Las funciones no pueden realizar de forma directa operaciones de entrada/salida (aunque existen estrategias para realizarlas indirectamente preservando a la función pura)
    • +
    + +

    Función como un TAD

    + +

    Las funciones currificadas, en tanto valores, pueden ser también pensandas como un TAD, para el cual:

    + +
      +
    • su única operación primitiva es la aplicación, definida entre una función y otro valor. Esta operación, a su vez también es una función, llamada apply, (función ($) en el Prelude de Haskell). Las demás operaciones complementarias, como la composición, se construyen a partir de la aplicación.
    • +
    • sus valores son cada una de las funciones posibles. Así, por ejemplo, even, odd, (+) son todos valores del tipo función
    • +
    + +

    Función desde el cálculo lambda

    + +

    Desde el punto de vista del cálculo lambda, la función es LA primitiva del lenguaje, y todas las funciones son anónimas, es decir, son expresiones lambda. Todo, hasta los números, pueden ser expresados con una función con suficiente imaginación.

    + +

    Funciones en Haskell

    + +

    Las funciones en Haskell presentan todas las carecterísticas mencionadas anteriormente. A modo de resumen, decimos que:

    + +
      +
    • Las funciones son transformaciones matemáticas, que presentan transparencia referencial, y por tanto libres de efecto
    • +
    • Las funciones son valores
    • +
    • Las funciones tienen tipo función ((->) a b), que está determinado por su dominio e imagen. Una función de enteros en booleanos tiene tipo Int -> Bool
    • +
    • Las funciones son un caso particular de las relaciones, que presentan unicidad y existencia para todo su dominio.
    • +
    • Las funciones están currificadas, por lo que no existen funciones de más de un argumento realmente, sino que se emulan a partir de funciones de un argumento que devuelven otra función que toma los parámetros restantes.
    • +
    • La operación primitiva de la función es la aplicación, por la cual se evalúa una función pasandole sus argumentos y obteniendo un resultado
    • +
    • El mecanismo de la evaluación de las funciones es la reducción (reducción 𝛃)
    • +
    • Dado que la única operación primitiva del tipo función es la aplicación, sólo es función aquello todo y sólo lo que pueda ser aplicado. Moraleja: no tiene sentido hablar de funciones de cero argumentos, ya que no pueden ser aplicadas
    • +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/conceptos-basicos-del-diseno.html b/wiki/articles/conceptos-basicos-del-diseno.html new file mode 100644 index 0000000000..f23b0d59b7 --- /dev/null +++ b/wiki/articles/conceptos-basicos-del-diseno.html @@ -0,0 +1,528 @@ + + + + + + + + + + + Conceptos basicos del diseno + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Conceptos basicos del diseno +

    +
    + + + + + +
    +

    Modelo

    + +

    Un modelo es una simplificación. Es una interpretación de la realidad que abstrae los aspectos relevantes para la solución de un problema. (Definición extraída de Domain Driven Design de Eric Evans.

    + +

    Dominio

    + +

    Todo programa de software que se va a construir, surge como una idea, o una necesidad, que está relacionada con alguna actividad o interés. Estas “actividades” o “intereses” y el conjunto de reglas y características que lo componen, son el dominio de un problema. Cuando vayamos a construir un programa, debemos conocer y entender el dominio para poder encarar una solución al problema que tenemos. Por supuesto que la información puede ser mucha, y en algunos casos difícil de entender, por lo que debemos crear modelos que simplifiquen, seleccionen y estructuren el conocimiento de manera de enfocarlo en lo que necesitamos para solucionar el problema.

    + +

    Heurística

    + +

    La heurística es una medida. No es una medida cuantitativa como una longitud o un peso, sino una medida que me permite establecer un valor de referencia de una característica cualitativa.

    + +

    Podemos hablar de que una heurística es una buena práctica, que permite comparar dos objetos de estudio en base a una determinada característica. No vamos a poder establecer un valor numérico para compararlos pero igualmente nos va a poder permitir saber si un objeto es “más” o “menos” que el otro en ese aspecto.

    + +

    Por ejemplo, si hablamos de la simplicidad de un diseño, no podemos decir que un sistema tenga complejidad 3.5 complejidoñios; pero sí podemos decir que un diseño es más o menos simple que otro.

    + +

    Las heurísticas son útiles cuando no disponemos de los medios cientificos para usar otras medidas.

    + +

    Es equivocado buscar que una heurística se convierta en un número medible, eso resulta contradictorio por su propia definición. Por lo tanto, en elementos cualitativos, es imposible establecer medidas cuantitativas. Aunque resulte tentador convertir una heurística en una medición debemos evitar esa tentación a todo costo.

    + +

    Por ejemplo un error común es hablar de complejidad en número de clases o número de métodos, de la misma manera que no podemos medir la complejidad de una solución por la cantidad de líneas de código involucradas. Estas medidas son apenas indicios pero es necesario analizar las clases, los métodos, el código para poder determinar si efectivamente esa solución resulta más compleja que otra.

    + +

    Cohesión

    + +
      +
    • Una clase es cohesiva si podemos definirle un objetivo claro y puntual.
    • +
    • Un método es cohesivo si tiene un único objetivo.
    • +
    + +

    Emitir una factura y calcular el total de facturación está bueno que estén en diferentes métodos. En general, tener métodos con efecto colateral (emitir factura, realizar un descuento, firmar una libreta de un alumno, cambiar el sueldo básico a un empleado) y métodos que no tengan efecto (conocer el sueldo de un empleado, saber el promedio de notas de un alumno en finales, conocer el total de facturación de un mes para un cliente, etc.) es una buena práctica, también es bueno abstraer ideas que se repiten en la misma clase dándole un nombre y dejándolo en un método aparte. Así por un lado evitamos duplicar código y por otro aumenta la cohesión de un método: se concentra en hacer sólo una cosa por vez.

    + +

    Por eso mismo un Cliente representa todo lo que un cliente puede abstraer. Si hay una clase Empresa es porque representa para nosotros una abstracción importante en el sistema, no para que la Empresa tome decisiones que son del cliente. El cliente tiene atributos + comportamiento. Así aumentamos la cohesión de nuestro sistema. De lo contrario, la Empresa toma responsabilidades de un Cliente, de un Empleado, etc. y como hace muchas cosas a la vez, el objetivo que cumple es difuso y la consecuencia de esta menor cohesión es el impacto que tiene cualquier modificación de la estructura interna de un cliente, un empleado o una factura.

    + +

    Acoplamiento

    + +

    Es el grado en que los componentes de un sistema se conocen.

    + +

    Un cliente conoce sus facturas para calcular el total, y está bien que las conozca. Lo que es nocivo para el cliente es conocer de más o de menos. De más porque si el cliente le pide las líneas (los renglones) a cada factura y luego a cada línea le pide el precio unitario de cada producto, cualquier modificación en el cálculo del precio de un producto (por ejemplo, descuento por cantidad dependiente del producto), el que se ve directamente afectado es el cliente.

    + +

    + Ejemplo de código con alto nivel de acoplamiento +

    + +
    +
    +
    +      public BigDecimal getMontoTotal() {
    +    BigDecimal total = new BigDecimal(0);
    +    for (Factura factura : this.facturas) {
    +        for (Renglon renglon : factura.renglones) { 
    +            total = total.add(renglon.getProducto().getPrecioUnitario() * renglon.getCantidad());
    +        }
    +    }
    +    return total;
    +}
    +
    +    
    +
    +
    + +

    Aquí vemos que un cliente conoce a objetos factura, pero también a renglones de factura y a productos.

    + +

    Si el cliente conoce de menos no tiene forma de saber el total de facturación si no sabe que cada factura tiene como interfaz un método que me permite saber el total

    + +
    +
    +
    +      public BigDecimal getTotal()
    +
    +    
    +
    +
    + +

    +
    +

    + +

    + El mismo ejemplo con nivel adecuado de acoplamiento entre cliente y factura +

    + +
    +
    +
    +      public BigDecimal getMontoTotal() {
    +    BigDecimal total = new BigDecimal(0);
    +    for (Factura factura : this.facturas) {
    +        total = total.add(factura.getTotal());
    +    }
    +    return total;
    +}
    +
    +    
    +
    +
    + +

    Acoplamiento explícito e implícito

    + +

    En algunos casos, el acoplamiento entre dos entidades de software no es fácilmente detectable, por lo que se llaman acoplamientos implícitos. Esto se produce cuando una entidad de software para su funcionamiento depende de una característica de otra que no está visible en su interfaz pública y en cambio forma parte de su implementación interna. En algunos libros este concepto puede encontrarse mencionado como Program to an interface, not to an implementation.

    + +

    El acoplamiento entre dos entidades de software produce una dependencia: un cambio en una de ellas posiblemente produzca un cambio en la otra. Al modificar una entidad de software es importante poder conocer cuáles son todas las otras entidades que pudieran ser afectadas por este cambio. Por eso, en el caso en que tengamos un acoplamiento, siempre es preferible que lo explicitemos, ya que facilitará la mantenibilidad del sistema y nos dará una herramienta para asegurar la consistencia ante las modificaciones.

    + +

    Requerimientos y casos de uso

    + +

    Un caso de uso es una secuencia de interacciones que se desarrollarán entre un sistema y sus actores en respuesta a un evento que inicia un actor principal sobre el propio sistema. Cuando hacemos especificaciones de los casos de uso definimos la interacción entre usuario y sistema, dejando claro el límite entre lo que debe proporcionar el usuario y lo que el sistema debe responder.

    + +

    Los casos de uso pueden ser útiles para establecer requisitos de comportamiento, pero no establecen completamente los requisitos funcionales ni permiten determinar los requisitos no funcionales. Los casos de uso deben complementarse con información adicional como reglas de negocio, requisitos no funcionales, diccionario de datos que complementen los requerimientos del sistema.

    + +

    Un requerimiento es algo que el sistema debe hacer para lograr el objetivo de un usuario.

    + +

    + Más sobre requerimientos +

    + +

    Links relacionados

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/conceptos-de-ingenieria-de-software-y-de-sistemas.html b/wiki/articles/conceptos-de-ingenieria-de-software-y-de-sistemas.html new file mode 100644 index 0000000000..d9efcaae98 --- /dev/null +++ b/wiki/articles/conceptos-de-ingenieria-de-software-y-de-sistemas.html @@ -0,0 +1,379 @@ + + + + + + + + + + + Conceptos de ingenieria de software y de sistemas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Conceptos de ingenieria de software y de sistemas +

    +
    + + + +
    +

    Ingeniería de software e ingeniería de sistemas

    + +

    ¿Qué es un sistema?

    + +

    Sistemas legacy, desarrollos a medida y enlatados

    + +

    Proceso de software

    + +

    Requerimientos

    + +

    Requerimientos funcionales

    + +

    Los requerimientos funcionales son las capacidades o funcionalidades de un sistema de software. Detallan el comportamiento del sistema. En otras palabras, lo que el sistema debe proveer. Hay distintos tipos de requerimientos no funcionales:

    + +

    Procesos de Negocio
    +Los procesos de negocios permiten especificar como un proceso se lleva a cabo a través de la organización, ya que requiere intervención de diferentes actores y áreas, en diferentes lugares y tiempos.

    + + + +

    Casos de Uso
    +Los caso de uso definen una interacción entre un actor y el sistema, para lograr un objetivo de negocio especifico en un lugar y momento especifico.

    + +

    Requerimientos no funcionales

    + +

    Los requerimientos no funcionales son aspectos que debe tener el sistema, estos pueden o no ser específicos de una funcionalidad (“el tiempo de respuesta para procesar el alta de una tarjeta SUBE vía web no debe exceder los 3 segundos” o “el sistema debe funcionar 7 x 24”), definen la calidad y las características que el sistema debe soportar. También conocidos como “atributos de calidad”, o “cualidades del software” algunos de estos son:

    + +
      +
    • Performance
    • +
    • Availability (Disponibilidad)
    • +
    • Security (Seguridad)
    • +
    • Testability (Testeabilidad)
    • +
    • Modifiability (Modificabilidad)
    • +
    • Usability (Usabilidad)
    • +
    + +

    Ejemplos de restricciones posibles:

    + +
      +
    • tecnológicas: “el sistema debe funcionar en un browser Internet Explorer 8 ó superior, Mozilla Firefox 5.0.3 y Safari en cualquier versión”, “tiene que construirse en una tecnología Open Source”, “tiene que ser Web based”
    • +
    • normativas o legales: “el sistema debe estar construido según estándares de ley Sarbanes-Oxley”, “el software debe contemplar que el proceso de fabricación de los productos se adapte a las normas ISO 9000”, “el sistema debe cumplir con el análisis de vulnerabilidad dispuesto por la gerencia de Seguridad Informática”
    • +
    • de calidad: disponibilidad: “el sistema debe estar disponible 6 x 20 / 7 x 24”, performance: “las consultas de cliente por nombre no pueden tardar más de 3 segundos”, escalabilidad: “se debe pemitir agregar nuevos tipos de cliente en el futuro”, usabilidad: “el sistema debe permitir a un usuario nuevo capacitarse en menos de una semana”.
    • +
    + +

    Más sobre cualidades del software

    + + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/configuracion-de-maven-para-poder-utilizar-las-herramientas-de-uqbar.html b/wiki/articles/configuracion-de-maven-para-poder-utilizar-las-herramientas-de-uqbar.html new file mode 100644 index 0000000000..b4b1dc2459 --- /dev/null +++ b/wiki/articles/configuracion-de-maven-para-poder-utilizar-las-herramientas-de-uqbar.html @@ -0,0 +1,365 @@ + + + + + + + + + + + Configuracion de maven para poder utilizar las herramientas de uqbar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Configuracion de maven para poder utilizar las herramientas de uqbar +

    +
    + + + +
    +

    Para poder utilizar los artefactos Maven desarrollados por Uqbar debemos agregar los repositorios de donde bajar los artefactos de Uqbar a la configuración de Maven. Esta configuración se debe indicar en el archivo settings.xml, que se ubica en:

    + +
      +
    • Windows: tu directorio de usuario + “.m2\settings.xml”. Por ejemplo, si tu usuario es Juana, e instalaste Windows en el disco C:, debería estar en “C:\Users\Juana.m2\settings.xml”
    • +
    • Linux: tu directorio de usuario (~) + “.m2/settings.xml”. Por ejemplo, si tu usuario es juana, debería estar en “~/.m2/settings.xml” o “/home/juana/.m2/settings.xml”
    • +
    + +

    Dado que .m2 es un directorio oculto, debés activar la configuración para verlos. Te dejamos las instrucciones para Windows y Linux

    + +

    El contenido de tu archivo settings.xml debería quedar así:

    + +
     <settings xmlns="http://maven.apache.org/POM/4.0.0"
    +            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    +            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    +   <profiles>
    +     <profile>
    +       <id>uqbar-wiki</id>
    +       <repositories>
    +         <repository>
    +           <id>uqbar-wiki.org-releases</id>
    +           <name>uqbar-wiki.org-releases</name>
    +           <url>http://maven.uqbar.org/releases</url>
    +         </repository>
    +         <repository>
    +           <snapshots/>
    +           <id>uqbar-wiki.org-snapshots</id>
    +           <name>uqbar-wiki.org-snapshots</name>
    +           <url>http://maven.uqbar.org/snapshots</url>
    +         </repository>
    +       </repositories>
    +     </profile>
    +   </profiles>
    +   <activeProfiles>
    +     <activeProfile>uqbar-wiki</activeProfile>
    +   </activeProfiles>
    + </settings>
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/configuraciones-generales-para-cualquier-eclipse.html b/wiki/articles/configuraciones-generales-para-cualquier-eclipse.html new file mode 100644 index 0000000000..f5dba3e258 --- /dev/null +++ b/wiki/articles/configuraciones-generales-para-cualquier-eclipse.html @@ -0,0 +1,513 @@ + + + + + + + + + + + Configuraciones generales para cualquier eclipse + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Configuraciones generales para cualquier eclipse +

    +
    + + + +
    +

    Hay varias cosas que es útil configurar en Eclipse, independientemente del lenguaje que elijan.

    + +

    Configuraciones adicionales de Eclipse

    + +

    Installed JRE

    + +

    + image +

    + +

    Una de las configuraciones más importantes, es el compilador que estará usando Eclipse para nuestro código Xtend. En el ejemplo de arriba, hemos configurado un compilador de Java 1.11 (consultá con tus docentes qué versión de JDK hay que usar). Es preciso recalcar que deben apuntar a una JDK (con el compilador) y no a una JRE o no podrán ejecutar ningún programa Xtend, ni Java.

    + +

    A continuación te dejamos una animación que muestra cómo configurar otra JDK, para lo cual hay que pasar el directorio raíz (no el bin donde residen el compilador y los demás programas de Java).

    + +

    + image +

    + +

    New > Artefactos de Xtend

    + +

    Para que cuando hagas New > File te aparezcan las clases y las interfaces Xtend, Window > Customize Perspective… > solapa Menu Visibility > expandís File > New > y seleccionás las de Xtend (Xtend class, inteface, annotation y enum).

    + +

    + image +

    + +

    Compiler

    + +

    Algunas versiones de Eclipse utilizan por defecto compatibilidad con el compilador Java 1.4, algo que no es conveniente si vamos a trabajar con herramientas como Generics o Annotations que vienen a partir del JDK 1.5.

    + +

    Para esto deben ir a Window Preferences > Java > Compiler > y donde dice JDK Compliance subir la propiedad “Compiler compliance level” de 1.4 a una superior.

    + +

    + java compiler configuration in eclipse +

    + +

    En caso contrario al bajar proyectos compilados en JDKs superiores aparecerán mensajes de error como estos:

    + +
    +
    +
    +      Syntax error, annotations are only available if source level is 1.5 or greater
    +Syntax error, parameterized types are only available if source level is 1.5 or greater
    +
    +    
    +
    +
    + +

    Encoding (sólo Windows)

    + +

    + image +

    + +

    Para no tener problemas con los tildes y demás caracteres especiales al bajarse los ejemplos conviene tener sincronizado el mismo encoding. Para eso, desde la barra de menú: Window > Preferences, filtrar por “encoding” y cambiar todos a “UTF-8” o “ISO 10646/Unicode(UTF-8)”. Por ejemplo: En General > Workspace > Text file encoding, seleccionar Other > UTF-8. Aplicar cambios.

    + +

    Spell

    + +

    + image +

    + +

    Si van a programar en español, es recomendable desactivar el diccionario (viene por defecto en inglés). Para ello filtrar en el menú por la palabra “spell” y desactivar la corrección ortográfica (Spelling > desactivar el check Enable spell checking). Aplicar cambios.

    + +

    Otra opción es que se bajen un diccionario español de internet y lo configuren.

    + +

    Warnings

    + +

    + image +

    + +

    En varios lenguajes de la JVM nos aparecerá una molesta advertencia sobre la serialización de clases, algo que por el momento no necesitamos. Conviene desactivar el warning default de clases serializables que no definan un identificador de versión: Window > Preferences, filtrar por “Serializable”, solapa Java / Compiler / “Errors/Warnings”, “Potential programming problems”, y se setea el valor de “Serializable class without serialVersionUID” a Ignore. Aplicar cambios.

    + +

    Opcionalmente, nosotros recomendamos subir a “Warning” estas dos configuraciones

    + +
      +
    • “Potential null pointer access”
    • +
    • “Redundant null check”
    • +
    + +

    Shortcuts

    + +

    En algunas distribuciones de Linux existe un shortcut por defecto que es Ctrl + Space, que colisiona con el shortcut del content assist de Eclipse . Para solucionar el problema, hay que deshabilitar el binding: en Ubuntu: System Settings -> Keyboard-> Shortcuts en Lubuntu: click en el logo que esta abajo a la izquierda -> Preferencias -> Metodos de entrada por Teclado y se cambia a “Disabled”

    + +

    Configuración de Maven

    + +

    Window > Preferences > Maven, debe tener esta configuración:

    + +

    + image +

    + +
      +
    • Download repository index on startup, al igual que Update Maven projects on startup deben estar destildados para evitar demoras al iniciar tu Eclipse
    • +
    • Por el contrario, Download Artifact Sources y Download Artifact JavaDoc deben estar tildados, porque eso descargará documentación y fuentes de los componentes que uses, algo bastante útil cuando necesitamos solucionar un error o entender de qué manera comunicarnos con él.
    • +
    • la marca Offline debe estar destildada, o no intentará conectarse a Internet para bajar componentes.
    • +
    + +

    Filtros de paquetes

    + +

    En un JDK estándar hay muchos paquetes, y sólo usaremos unos pocos. Es recomendable indicarle a Eclipse que no nos sugiera paquetes que casi con seguridad no usaremos.

    + +

    Para eso, en Java > Appearance > Type Filters, agregar las siguientes expresiones:

    + +
    +
    +
    +      bash
    +sun.*
    +*.internal.*
    +edu.emory.mathcs.backport.*
    +java.awt.*
    +java.swing.*
    +org.omg.*
    +
    +    
    +
    +
    + +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/conocimiento-de-dominio-y-refactoring.html b/wiki/articles/conocimiento-de-dominio-y-refactoring.html new file mode 100644 index 0000000000..d8c94b2551 --- /dev/null +++ b/wiki/articles/conocimiento-de-dominio-y-refactoring.html @@ -0,0 +1,335 @@ + + + + + + + + + + + Conocimiento de dominio y refactoring + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Conocimiento de dominio y refactoring +

    +
    + + + +
    +

    ¿Se puede iniciar un refactoring sin conocimiento del dominio?

    + +

    ¿Se puede refa La respuesta corta es: no, no se puede (*) realizar un refactor sin conocimiento del dominio.

    + +

    Ahora sí, la respuesta larga.

    + +

    Primero, aclaremos algunas ideas:

    + +

    “dicen que no necesitan conocerlo para hacer un refactoring”

    + +

    Ojo, lo que comentamos en clase fue que no necesito conocer el dominio para identificar potenciales fallas en el diseño, que se manifiestan a través del código. Es decir, sin conocimiento de dominio podemos sólo identificar code smells, que tienen asociados posibles refactors.

    + +

    Sí, remarco el posible/potencial porque es importante que entendamos que se trata sólo de una heurística. Quizás el diseño sí es correcto, o quizás el refactor que deberíamos encarar no tiene nada que ver con lo que propone el code smell. Por eso, también ojo con esto:

    + +

    “pero no hace falta saber nada acerca del dominio para darte cuenta que tenes q delegar en subclases en ves de preguntar por el tipo”

    + +

    Esto tampoco es correcto, si bien es muy probable que haya que emplear polimorfismo (y no necesariamente utilizar herencia), necesitaremos conocer al dominio y a la tecnología como para poder justificar ese cambio (**) . De lo contrario, si pensaramos que para toda estructura de código que se corresponde con un code smell hay un cambio que tenemos que realizar, estariamos (casi) insinuando que hay aspectos del diseño automatizables. Yo prefiero descreer de esto.

    + +

    En resumen hasta acá, parafraseándote, no necesito conocer al dominio para encontrar code smells, pero sí lo necesito para saber si efectivamente hay una falla de diseño, y en tal caso, determinar el refactor más apropiado que los subsane.

    + +

    Pero este otro comentario:

    + +

    “si el sistema tiene un elevado nivel de acoplamiento, hacer un refactoring de algo te lleva a cambiar 90 cosas más…que a menos que sepas como viene el sistema y cuál es la funcionalidad de cada parte y su dependencia, no lo vas a poder hacer”

    + +

    me lleva a otra pregunta: supongamos que tenemos conocimiento del dominio; ¿podemos realizar un refactor sin conocimiento del diseño actual? Se los dejo para pensar, sería interesante si alguien se anima proponer una solución al dilema (sic).

    + +

    Y finalmente, buena observación:

    + +

    “después de cada modificación en el diseño hay q actualizar la documentación”

    + +

    sí, si modificamos el diseño de un sistema, deberíamos impactarlo en la documentación que llevemos de este. Como eso puedo ser tedioso, y en los momentos iniciales del desarrollo de un sistema los cambios de diseño son constantes, es frecuente postergar la realización de una documentación exhaustiva hasta que el diseño a más alto nivel (llamémoslo arquitectura) quede estabilizado.

    + +

    Saludos!

    + +

    (*) “no se puede” en sentido informal: es ciertamente posible hacerlo, pero no es una gran idea, por lo expuesto precisamente por vos, al menos para bases de código (proyectos) no triviales.

    + +

    Por ejemplo, en nuestro ejercicio de monedero, el dominio era muy simple: poner y sacar dinero en una cuenta, llevando un historial del mismo, y validando algunas reglas de negocio, por eso con apenas algunos minutos de análisis podíamos saber qué refactorizar. Pero en sistemas con dominios más complejos y muchas más tecnologías involucradas, hubiéramos necesitado mucho más tiempo para determinar exactamente qué hacer.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/creacion-de-objetos--con-parametros.html b/wiki/articles/creacion-de-objetos--con-parametros.html new file mode 100644 index 0000000000..19882d5534 --- /dev/null +++ b/wiki/articles/creacion-de-objetos--con-parametros.html @@ -0,0 +1,386 @@ + + + + + + + + + + + Creacion de objetos con parametros + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Creacion de objetos con parametros +

    +
    + + + +
    +

    Eso, lo que dijo Leo. Pero algunas cositas más …

    + +

    En Smalltalk no hay constructores, hay mensajes y ya.

    + +

    Todos los mensajes devuelven un objeto (p.ej. cuando le ponés el ^ sombrerito). Los métodos que no tienen el sombrerito, es como si abajo de todo dijeran ^self.

    + +

    p.ej. Golondrina >> energia: unaEnergia

    + +

            "Setter de la variable energia" +        energia := unaEnergia. +        ^self

    + +

    Entonces no hay constructores, pero podemos hablar de mensajes que le mandamos a la clase (mensajes de clase) y que devuelven una instancia de esa clase. Lo que podés hacer es implementar tus propios métodos de clase.

    + +

    El mensaje new no recibe parámetros, así que con new no vas a poder hacer eso que decís

    + +

    p.ej.

    + + pepita := Golondrina nuevaEnergiaInicial: 100 ubicacionActual: buenosAires. <\\En un workspace> + +El objeto que recibe el mensaje es la clase Golondrina, entonces self dentro del método \#nuevaEnergiaInicial:ubicacionActual: apunta a la clase Golondrina + +------------------------------------------------------------------------ + +(Método de clase de Golondrina) nuevaEnergiaInicial: unaEnergia ubicacionActual: unLugar + +`    | nuevaGolondrina |` + +`    "Instanciamos una nueva Golondrina, acordate que self apunta a la clase Golondrina en este ejemplo"` +`    nuevaGolondrina := self new.` + +`    "Le mandamos el mensaje energia: a la nueva instancia"` +`    nuevaGolondrina energia: unaEnergia.` + +`    "Le mandamos el mensaje ubicacion: a la nueva instancia"` +`    nuevaGolondrina ubicacion: unLugar.` + +`    "Si no escribimos nada más devolvería self, en este caso la clase Golondrina, y se rompería todo en el workspace cuando le empecemos a hablar a pepita (que apuntaría a la clase Golondrina en vez de a una nueva instancia"` + +`    "Por todo eso agregamos"` +`    ^nuevaGolondrina` + +------------------------------------------------------------------------ + +De todas formas en el propio workspace se puede instanciar en menos líneas sabiendo que los mensajes que son setters devuelven el objeto receptor de ese mensaje + +"Puse los paréntesis en rojo para que se entienda más, pero no son necesarios" + +pepita := ((Golondrina new) energia: 100) ubicacion: buenosAires. + +Como es peligroso asumir eso y no ayuda a la expresividad, se puede usar un operador punto y coma <;> (que es un chiche sintáctico de Smalltalk) para mandar mensajes en cascada. + +Object >> yourself + +`         "El mensaje yourself devuelve self, cuac!"` +`         ^self` + +Escribir pepita := Golondrina new. + +Es igual a escribir pepita := (Golodrina new) yourself. + +Escribir "Evaluar todo esto nos devuelve una instancia de la clase Golondrina, con 100 de energia y con buenosAires como ubicación" pepita := Golondrina new. pepita energia: 100. pepita ubicacion: buenosAires. pepita. + +Es lo mismo que pepita := + +`       Golondrina new` +`               energia: 100;` +`               ubicacion: buenosAires;` +`               yourself` + +Bue, me pareció copado contar todo esto :$ + +Si no se entendió algo pruébenlo, usen el inspect y tiene que salir. O de última, vuelvan a preguntar =P + +Saludos, + +El 9 de mayo de 2009 14:16, Leonardo "Pelado" Cesario <peladosnow@gmail.com> escribió: + +`   Hernan:` +`   Primero te preguntaria si ya viste metodos de clase.` +`   En caso afirmativo vos podes hacer tu metodo de creacion, por ejemplo new:` +`   No es verdad que el new envia el mensaje initialize (por lo menos no pasa en todas las versiones de ST)` +`   Si podes redefinir el new para que llame al initialize. De todas formas la idea del initialize es inicializar (cuak!) el estado interno, no de pasarle parametros.` +`   El tema de si lo creo con parametros o luego se los mando por medio de otro mensaje, es un tema de diseño.` +`   Espero se aclare la duda y te ayude a decidir.` +`   Saludos!` +`   Leo C` + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/creacion-de-un-proyecto-maven-basico.html b/wiki/articles/creacion-de-un-proyecto-maven-basico.html new file mode 100644 index 0000000000..164a1c5848 --- /dev/null +++ b/wiki/articles/creacion-de-un-proyecto-maven-basico.html @@ -0,0 +1,430 @@ + + + + + + + + + + + Creacion de un proyecto maven basico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Creacion de un proyecto maven basico +

    +
    + + + +
    +

    El objetivo de este tutorial es crear una aplicación base utilizando las siguientes tecnologías:

    + +
      +
    • Java
    • +
    • Eclipse
    • +
    • Git
    • +
    • Maven
    • +
    + +

    Se asume la presencia de un entorno con todas esas herramientas configuradas adecuadamente. En caso de duda recomendamos ir al siguiente link.

    + +

    Creación del proyecto

    + +

    Paso 1: Creación del proyecto Maven

    + +

    Desde el menú principal del Eclipse seleccionamos File > New… Project… Maven Project. En la primera pantalla del asistente

    + +
      +
    • podemos elegir un archetype, o bien chequear la opción “Create a simple project (skip archetype selection)” que es la opción por defecto que vamos a elegir.
    • +
    + +

    Al presionar Next, nos aparece el siguiente paso, donde debemos elegir

    + +
      +
    • +

      el Group Id refleja la organización para la que vamos a construir el proyecto (por lo general depende de la materia que estás cursando)

      +
    • +
    • +

      el Artifact Id que se asocia al nombre del proyecto

      +
    • +
    • +

      la versión, donde dejamos el valor por defecto

      +
    • +
    + +

    Creación de un proyecto Maven en Eclipse

    + +

    Paso 2: Agregar bibliotecas necesarias al pom

    + +

    En el archivo pom.xml del raíz del proyecto podemos agregar bibliotecas a nuestro proyecto en el nodo dependencies…

    + +
    <dependencies>
    +   <dependency>
    +       <groupId>log4j</groupId>
    +       <artifactId>log4j</artifactId>
    +       <version>1.2.13</version>
    +   </dependency>
    +   <dependency>
    +       <groupId>commons-collections</groupId>
    +       <artifactId>commons-collections</artifactId>
    +       <version>3.1</version>
    +   </dependency>
    +</dependencies>
    +
    + +

    También podemos cambiar el groupId, artifactId, la versión o bien apuntar a un parent project (para mayor información consulte con el docente de su materia)

    + +

    Paso 3: Importación de la información al entorno

    + +

    Cada vez que se modifique el archivo pom.xml, debemos actualizar nuestro entorno (Eclipse, IntelliJ o el que fuera) mediante un botón derecho sobre el proyecto Maven > Update project, o bien por línea de comando hacer:

    + +
    mvn eclipse:eclipse -DdownloadSources=true -DdownloadJavadocs=true
    +
    + +

    Cómo encontrar bibliotecas

    + +

    Si no estamos seguros del nombre o la última versión de un componente, podemos hacer la correspondiente búsqueda en http://search.maven.org

    + +

    Definir repositorios adicionales

    + +

    Si tenemos bibliotecas que no podamos encontrar en el repositorio default de maven (repo1.maven.com), debemos agregar un repositorio adicional. Hay muchas formas de hacer esto, una sencilla es agregarlo en el pom, antes de las dependencias. Un repositorio posible para esta tarea es el de JBoss, para agregarlo pueden hacer:

    + +
    <repositories>
    +   <repository>
    +      <id>jboss</id>
    +      <url>http://repository.jboss.org/maven2</url>
    +   </repository>
    +</repositories>
    +
    + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/crear-un-proyecto-en-xp-dev.html b/wiki/articles/crear-un-proyecto-en-xp-dev.html new file mode 100644 index 0000000000..8e5b83a38c --- /dev/null +++ b/wiki/articles/crear-un-proyecto-en-xp-dev.html @@ -0,0 +1,340 @@ + + + + + + + + + + + Crear un proyecto en xp dev + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Crear un proyecto en xp dev +

    +
    + + + +
    +

    Crear una cuenta de usuario en xp-dev

    + +

    … pendiente

    + +

    Crear un proyecto en xp-dev

    + +

    Creación del proyecto

    + +

    Una vez logueados en el sitio de xp-dev, en la solapa de “My Projects”, abajo de todo se puede ver el formulario “Create a New Project”.

    + +

    Al completar el formulario se recomienda elegir la opción “Trak” como source control. Luego clickear en “Create Project.

    + +

    Creación del repositorio svn

    + +

    En la página siguiente elegir la solapa “Source Control” y ahí seguir el link: Enable Source Control. En el formulario seleccionar la opción “Create Initial Directories” y clickear sobre “Save”.

    + +

    En la página resultante se mostrará la URL del repositorio que se acaba de crear, por ejemplo:

    + +
    http://svn2.xp-dev.com/svn/proyecto-de-prueba
    +
    + +

    Es importante registrar esa URL para poder publicar sus proyectos ahí.

    + +

    Configuraciones Adicionales

    + +

    Eligiendo la solapa “Settings” y desde esa página la opción “Permissions” se pueden realizar invitaciones a otros usuarios, clickeando sobre “Assign Permission To New User”.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/css.html b/wiki/articles/css.html new file mode 100644 index 0000000000..51681cae7f --- /dev/null +++ b/wiki/articles/css.html @@ -0,0 +1,674 @@ + + + + + + + + + + + Css + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Css +

    +
    + + + + + +
    +

    Es la forma más recomendada de especificar y modificar las cuestiones estéticas de una página HTML. La característica principal es que separa estas declaraciones del propio html. Así evita ensuciar la información (html) con cuestiones estéticas (el archivo .css). Además permite reutilizar estilos entre las diferentes páginas html, manteniendo consistencia entre el estilo de todo el sitio/aplicación.

    + +

    Sintaxis

    + +

    CSS tiene su propio lenguaje declarativo en el cual especificamos reglas. Una regla tiene la siguiente sintaxis:

    + +

    + css rule +

    + +

    El selector nos permite aplicar el estilo a aquellos elementos que coincidan con dicha expresión. Luego el cuerpo de la regla contiene un conjunto de propiedades y valores para éstos.

    + +

    Algunas propiedades aplican solo a algunos tipos de tags. Sin embargo, no es un lenguaje que “compile” o que tire errores. Simplemente si una propiedad no aplica a un tag, el browser no le va a dar bola.

    + +

    Un primer ejemplo para entender la sintaxis

    + +
    +
    +
    +      span {
    +   text-align:center;
    +}
    +
    +    
    +
    +
    + +

    Aplica el valor “center” a la propiedad “text-align” de todos los tags de la página que sean de tipo <span> (en otras palabras, alinea un texto en el centro de donde está contenido).

    + +

    Selectores Principales

    + +

    Básicamente lo primero que tenemos que saber sobre los selectores es que hay tres grandes tipos o formas de matchear nuestros tags.

    + +
      +
    • Por tag, es decir a todos los tags de un tipo (por ejemplo h1, h2, etc).
    • +
    • Por clase (class), es decir a los tags a los que se les haya indicado un estilo determinado (mediante el atributo class).
    • +
    • Por id, es decir a un elemento específico de la página según su id.
    • +
    + +

    Ejemplo por tag (ya vimos otro arriba para <span>)

    + +
    +
    +
    +      td {
    +   text-align:center;
    +   color:red;
    +}
    +
    +    
    +
    +
    + +

    Aplica esas dos propiedades a todos los <td>

    + +
    +
    +
    +      .filaImpar {
    +   text-align:center;
    +   color:red;
    +}
    +
    +    
    +
    +
    + +

    Este selector, que comienza con un punto, indica que va a matchear con cualquier tag (no importa el tipo de tag), siempre que éste tenga el valor filaImpar en su atributo class. Por ejemplo matchearía con estos tags:

    + +
    +
    +
    +      <p class="filaImpar">Hola Soy un P&aacute;rrafo<p>
    +
    +<span class="filaImpar importante">Hola Soy un Span<p>
    +
    +<tr class="conBordes fondoImportante filaImpar">
    +     <td>Hola, soy una Fila</td>
    +<tr>
    +
    +    
    +
    +
    + +

    Como se ve en el ejemplo anterior, un tag puede tener más de un class. Así los classes no tienen nada que ver con las clases de un lenguaje orientado a objetos. Pueden pensarlos más bien como “labels” o “etiquetas” o marcas que pongo a los tags, para luego por CSS agregarle características visuales. Así eventualmente uno en un proyecto grande, se crearía su propia convención con un conjunto de “classes” que reutilizaría en todo su sitio. Por ejemplo “titulo” o “menu”, “botonGrande”, “botonMediano”, etc. Es una buena forma de elevar el nivel del html con nuevos significados.

    + +

    El último ejemplo, matchear por id

    + +
    +
    +
    +      #unElementoEspecifico {
    +   text-align:center;
    +   color:red;
    +}
    +
    +    
    +
    +
    + +

    Este selector es el más “puntual” o específico, y permite matchear con tags, no importa su tipo, ni tampoco su class, sino que solo busca por “id”.

    + +
    +
    +
    +      <li id="opcionIrAAyuda">Ir a Ayuda</li>
    +<button id="volver">Volver</button>
    +
    +    
    +
    +
    + +

    Como en una página no deberían existir dos tags con el mismo id sin importar en qué tag o nivel se encuentre es el mecanismo menos recomendable para trabajar.

    + +

    Uso de CSS desde HTML

    + +

    El html usa el css mediante una declaración en la sección HEAD.

    + +
    +
    +
    +      <html>
    +     <head>
    +          ...
    +          <link rel="stylesheet" type="text/css" href="styles.css" />
    +          ...
    +     </head>
    +</html>
    +
    +    
    +
    +
    + +

    Donde “styles.css” sería mi archivo de estilos y estaría, en este caso en la misma carpeta en que se encuentra este html. También podríamos usar una URL absoluta:

    + +
    +
    +
    +      <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
    +
    +    
    +
    +
    + +

    Existen otras formas de incluir estilos en un html, sin embargo la mejor es la que ya citamos. Las demás involucran ensuciar el html, y las pueden ver en este link

    + +

    Cascada

    + +

    Las reglas se aplican en cascada, esto significa dos cosas:

    + +
      +
    1. En primer lugar cada componente hereda determinados estilos de sus contenedores, por ejemplo un td (celda de una tabla) hereda los del tr (fila) y del table correspondientes. Los estilos que apliquen al componente específico sobreescriben a los del contenedor, pero aquellos que no estén especificados se heredan. No todas las indicaciones de estilo son “heredables” (inheritable en inglés), es importante entender el comportamiento de cada una de las diferentes indicaciones de estilo.
    2. +
    3. En segundo lugar sobre cada componente pueden aplicarse más de un estilo, que matcheen con ese componente según su tag, class y id respectivamente. Esos diferentes estilos se van a combinar permitiendo que el estilo más específico sobreescriba los estilos más generales, pero aun manteniendo las indicaciones correspondientes al estilo más general que no sean redefinidas.
    4. +
    + +

    Ejemplo de varias reglas aplicando al mismo tiempo sobre un tag.

    + +
    +
    +
    +      tr {
    +   text-align:center;
    +}
    +
    +.resaltar {
    +   background-color: red;
    +}
    +
    +    
    +
    +
    + +

    Ambas reglas van a aplicar en este tag

    + +
    +
    +
    +      <tr class="resaltar">
    +     <td>Hola, soy una celda</td>
    +</tr>
    +
    +    
    +
    +
    + +

    El texto se va a ver centrado y además con fondo rojo.

    + +

    Combinando Selectores (OR)

    + +

    Es común que tengamos que aplicar los mismos estilos a diferentes tags. Para evitar duplicación de código las reglas se pueden combinar. Ej:

    + +
    +
    +
    +      h1 {
    +  text-align:center;
    +  color:red;
    +}
    +h2 {
    +  text-align:center;
    +  color:red;
    +}
    +p {
    +  text-align:center;
    +  color:red;
    +}
    +
    +    
    +
    +
    + +

    Se puede refactorizar a esto:

    + +
    +
    +
    +      h1, h2, p {
    +  text-align:center;
    +  color:red;
    +}
    +
    +    
    +
    +
    + +

    La sintaxis entonces es:

    + +
    +
    +
    +      selector1, selector2, ... selectorN {
    +     propiedad1: valor1;
    +     propiedad2: valor2;
    +     ...
    +     propiedadN: valorN;
    +}
    +
    +    
    +
    +
    + +

    Se puede pensar como un or. Sería, si es un h1 o es un h2, o es un p.

    + +

    Ventajas del uso de CSS

    + +

    La separación de concerns (layout vs. configuración estética) permite dos cosas:

    + +
      +
    • +

      Configurar y personalizar el estilo que se muestre por usuario/región/dispositivo y preservar el lema DRY (Don’t repeat yourself), la página HTML aumenta su expresividad (es más fácil de entender) los diseñadores gráficos se concentran el look & feel, decorando los botones, las tablas (grillas), el tipo de letra, los títulos y también los logos, isotipos e imágenes que la aplicación va a tener. Por lo general reciben un “esqueleto” de las páginas con datos de prueba escritos en forma manual

      +
    • +
    • +

      Por otra parte, los programadores se concentran en la lógica de presentación y en la facilidad de uso por parte del usuario

      +
    • +
    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/cual-es-la-diferencia-entre-una-tupla-y-una-lista-.html b/wiki/articles/cual-es-la-diferencia-entre-una-tupla-y-una-lista-.html new file mode 100644 index 0000000000..72e30aaeb5 --- /dev/null +++ b/wiki/articles/cual-es-la-diferencia-entre-una-tupla-y-una-lista-.html @@ -0,0 +1,423 @@ + + + + + + + + + + + cual es la diferencia entre una tupla y una lista + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + cual es la diferencia entre una tupla y una lista +

    +
    + + + +
    +

    En primer lugar vale la pena detenernos a pensar qué queremos modelar al usar tuplas y listas. La tupla representa una agrupación de valores ordenados, cada uno con un significado particular ya que se intenta modelar una abstracción compuesta por todos estos elementos. En estructurado podemos compararlas con los registros. Las listas sirven para modelar conjuntos de elementos, para agrupar valores independientes entre sí.

    + +

    Tuplas y listas en Haskell

    + +

    Una cosa que suele confundir a la hora de diferenciar listas y tuplas es la idea de que “el número de componentes de una tupla es fijo”, ¿qué quiere decir que es fijo si yo puedo tener 2-uplas, 3-uplas… n-uplas?

    + +

    Lo que quiere decir es que las tuplas de distinta aridad son de distinto tipo, es decir no son comparables entre sí. Es decir la tupla (a,a) y la tupla (a,a,a) son de tipos distintos y yo no puedo hacer una función que acepte ambas tuplas 1.

    + +

    En cambio, las listas sí son ambas del mismo tipo ([a]) y entonces sí puedo hacer una función que funcione en ambos casos.

    + +

    Ejemplos básicos

    + +

    Comencemos por ver qué tipos me dice el Haskell que tiene cada uno de los valores que mencionamos antes:

    + +
    Prelude> :t (True, True)
    +(True, True) :: (Bool, Bool)
    +
    +Prelude> :t (True, True, True)
    +(True, True, True) :: (Bool, Bool, Bool)
    +
    +Prelude> :t [True, True]
    +[True, True] :: [Bool]
    +
    +Prelude> :t [True, True, True]
    +[True, True, True] :: [Bool]
    +
    + +

    Lo que hay que mirar en el ejemplo anterior es que las dos tuplas tienen tipos distintos ((Bool, Bool) y (Bool, Bool, Bool)), mientras que las dos listas tienen el mismo tipo ([Bool]).

    + +

    Además podemos ver que el tipo de una tupla indica la cantidad de componentes, mientras que el tipo de una lista no… eso quiere decir que todas las listas de booleanos son del mismo tipo, independientemente de la cantidad de componentes.

    + +

    Errores de tipo

    + +

    Es fácil ver que si intentamos trabajar con las dos tuplas como si fueran del mismo tipo vamos a tener problemas, un ejemplo sencillo es compararlas por igualdad. Si comparamos las dos listas obtenemos el resultado esperable:

    + +
    Prelude> [True,True] == [True,True,True]
    +False
    +
    + +

    pero si intentamos comparar las dos tuplas ocurre un error:

    + +
    Prelude> (True,True) == (True,True,True)
    +<interactive>`:1:15:`
    +`     Couldn't match expected type `(Bool, Bool)' `
    +`            against inferred type `(Bool, Bool, Bool)' `
    +`     In the second argument of `(==)', namely `(True, True, True)' `
    +`    In the expression: (True, True) == (True, True, True) `
    +`     In the definition of `it': it = (True, True) == (True, True, True) `
    +
    + +

    Uso en funciones

    + +

    También podemos ver que una función puede manejar listas de cualquier longitud pero no pasa lo mismo con las tuplas. Si intentamos hacer una función todosVerdaderos, con listas es fácil:

    + +
    todosVerdaderosL [] = True
    +todosVerdaderosL (x:xs) = x && todosVerdaderosL xs
    +
    + +

    Al cargar eso en el Haskell obtenemos:

    + +
    Prelude> :l todosVerdaderos.hs
    +[1 of 1] Compiling Main             ( todosVerdaderos.hs, interpreted )
    +Ok, modules loaded: Main.
    +*Main> todosVerdaderosL [True,True]
    +True
    +*Main> todosVerdaderosL [True,True,True]
    +True
    +
    + +

    Podríamos intentar hacer lo mismo con tuplas, para ello agrego las dos definiciones:

    + +
    todosVerdaderosT (x,y) = x && y
    +todosVerdaderosT (x,y,z) = x && y && z
    +
    + +

    Pero lamentablemente eso no es posible en Haskell:

    + +
    *Main> :r
    +[1 of 1] Compiling Main             ( todosVerdaderos.hs, interpreted )
    +todosVerdaderos.hs:5:17:
    +`     Couldn't match expected type `(Bool, Bool)' `
    +`            against inferred type `(a, b, c)' `
    +    In the pattern: (x, y, z)
    +`     In the definition of `todosVerdaderosT': `
    +`        todosVerdaderosT (x, y, z) = x && y && z
    +Failed, modules loaded: none.
    +
    + +

    Una forma de definir la función es:

    + +
    todosVerdaderosT2 (x,y) = x && y
    +todosVerdaderosT3 (x,y,z) = x && y && z
    +
    + +

    eso si pasa los chequeos del haskell:

    + +
    Prelude> :r
    +[1 of 1] Compiling Main             ( todosVerdaderos.hs, interpreted )
    +Ok, modules loaded: Main.
    +
    + +

    Pero vemos que me obliga a usar las funciones separadamente:

    + +
    *Main> todosVerdaderosT2 (True,True)
    +True
    +*Main> todosVerdaderosT3 (True,True,True)
    +True
    +
    + +

    Finalmente, podemos ver que si se intenta intercambiar las funciones se produce un error:

    + +
    *Main> todosVerdaderosT2 (True,True,True)
    +<interactive>`:1:18:
    +`     Couldn't match expected type `(Bool, Bool)' `
    +`            against inferred type `(Bool, Bool, Bool)' `
    +`     In the first argument of `todosVerdaderosT2', namely `
    +`         `(True, True, True)' `
    +    In the expression: todosVerdaderosT2 (True, True, True)
    +`     In the definition of `it': `
    +        it = todosVerdaderosT2 (True, True, True)
    +
    + +

    Para más información, ver acá: Pattern_Matching_en_Haskell

    + +

    1 En realidad una función sí podría recibir tuplas de distinto tipo, si la función es polimórfica. Pero eso escapa el objetivo del presente artículo.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/cuando-usar-parentesis.html b/wiki/articles/cuando-usar-parentesis.html new file mode 100644 index 0000000000..cf2c80ccda --- /dev/null +++ b/wiki/articles/cuando-usar-parentesis.html @@ -0,0 +1,361 @@ + + + + + + + + + + + Cuando usar parentesis + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Cuando usar parentesis +

    +
    + + + +
    +

    A diferencia de matemática y muchos lenguajes (como C o Java) en Haskell no es necesario utilizar paréntesis al pasarle los parámetros a una función. Es decir, si tenemos una función de un parámetro en matemática lo escribimos con paréntesis: ; mientras tanto, en Haskell, simplemente se pone el parámetro al lado de la función .

    + +

    En el caso de tener más de un parámetro en matemática estamos acostumbrados a separarlos con comas, por ejemplo: ; en Haskell tampoco se utiliza esa sintaxis. En cambio simplemente se ponen los parámetros uno al lado del otro, separados por espacios:

    + +

    Entonces los paréntesis se usan únicamente para

    + +
      +
    • Alterar la precedencia
    • +
    • Tuplas
    • +
    • Usar operadores sin aplicarles todos los parámetros, caso típico (+) o (+1).
    • +
    + +

    Alterar la precedencia

    + +

    Antes que nada hay que entender qué significa el Concepto de Precedencia en un lenguaje de programación.

    + +

    Los paréntesis permiten naturalmente alterar la precedencia propia del lenguaje, por ejemplo si evaluamos

    + +

    2 + 3 * 4

    + +

    obtendremos como resultado 14, ya que la multiplicación tiene mayor precedencia que la suma; utilizando paréntesis podemos alterar ese comportamiento, si escrigimos

    + +

    (2 + 3) * 4

    + +

    podemos lograr que la operación de suma se ejecute “antes” que la multiplicación y obtener 20 como resultado.

    + +

    Para poder utilizar esto eficientemente, hay que tener algún conocimiento de la Precedencia de los operadores más comunes en Haskell.

    + +

    Ejemplos

    + +

    … TBC …

    + +

    Tuplas

    + +

    … TBC …

    + +

    Aplicación parcial de operadores

    + +

    … TBC …

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/cuestiones-basicas-para-resolver-el-parcial-de-objetos.html b/wiki/articles/cuestiones-basicas-para-resolver-el-parcial-de-objetos.html new file mode 100644 index 0000000000..e271a75870 --- /dev/null +++ b/wiki/articles/cuestiones-basicas-para-resolver-el-parcial-de-objetos.html @@ -0,0 +1,455 @@ + + + + + + + + + + + Cuestiones basicas para resolver el parcial de objetos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Cuestiones basicas para resolver el parcial de objetos +

    +
    + + + +
    +

    Esta es una recopilación de errores comunes a la hora de resolver un parcial de objetos. Son conceptos muy básicos, es decir, esto debe considerarse como “condiciones necesarias” para aprobar el parcial; nunca como “condiciones suficientes”.

    + +

    Conceptos básicos

    + +

    Utilizar los conceptos del paradigma
    +Encontrar abstracciones, aprovechar el polimorfismo, delegar responsabilidades, etc.

    + +

    Hay que programar con objetos, no vale programar como si fuera Algoritmos… para aprender eso ya está Algoritmos.

    + + + +

    Repartir las responsabilidades
    +Que no me quede todo el código en un mismo objeto. Es fácil verlo (por ejemplo) cuando una caja del diagrama de clases ocupa la mitad de la página.

    + +

    Que no todos los mensajes del workspace vayan al mismo objeto.

    + +

    Que no haya un objeto “Sistema”.

    + + + +

    Ser consistente
    +Por ejemplo:

    + +
      +
    • Si en algún lugar mando un mensaje y trato el resultado como una colección debo asegurarme de que la implementación del método devuelva una colección (lo mismo vale para colecciones como para cualquier otro objeto).
    • +
    • Si tengo muchos métodos polimórficos todos deben recibir los mismos parámetros y devolver objetos del mismo tipo.
    • +
    • En un método puedo usar las variables de instancia del objeto o los parámetros, cualquier otra variable “mágica” que aparezca constituye un error.
    • +
    + + + +

    Ser específico
    +Indicar las relaciones de conocimiento en el diagrama de objetos.

    + +

    También los atributos que tiene cada objeto.

    + +

    También tiene que quedar claro de qué tipo es cada parámetro que espera un método, y qué devuelve.

    + + + +

    Elegir buenos nombres para clases, métodos y variables
    +Por ejemplo diferenciar desde el nombre los métodos que son órdenes de los que son consultas. Para los primeros conviene usar oraciones en infinitivo o en imperativo. Para las consultas en general usamos el indicativo:

    + +
      +
    • “caminá” o “caminar” podrían indicar la orden de realizar una caminata (en el parcial vale poner el acento para que se note la intención).
    • +
    • “caminaste” podría ser una consulta que devuelve un booleano indicando si caminó
    • +
    • “cuantoCaminaste” podría ser una consulta que devuelve una cantidad.
    • +
    • Por otro lado, un nombre como “caminata” dificulta comprender la intención.
    • +
    + +

    Esto es aún más importante si el método en cuestión no está 100% correcto, ya que al menos permite entender lo que quisieron hacer.

    + +

    Cosas básicas de Smalltalk

    + +

    Si bien no es nuestro objetivo saber bocha de Smalltalk, hay cositas que impactan directamente en la posibilidad o no de comprender lo que están programando; entonces conviene darles bola:

    + +

    Tienen la guía de lenguajes, ¡úsenla!
    +Por ejemplo deberían aprovecharla para saber qué mensajes entiende una colección, no hace falta acordárselos de memoria para usarlos correctamente.

    + + + +

    No confundir mensajes con variables
    +Y además ser bien explícito en el diagrama y en el código, cuándo están enviando un mensaje y cuándo están accediendo a una variable de instancia.

    + + + +

    La sintaxis es objeto-mensaje-parámetro…
    +¡No da confundirse con eso!

    + + + +

    Identificar bien mayúsculas y minúsculas.
    +Los nombres de clase van con mayúscula, al igual que las variables de clase.

    + +

    Todo lo demás va en minúscula.

    + +

    Romper estas reglas obliga a que el corrector tenga dudas de lo que están haciendo.

    + +

    El diagrama de clases

    + +

    ¡Debe ser conexo!
    +No vale sólo dibujar las cajitas con los métodos y atributos, las relaciones entre los objetos son igual de importantes. Una clase que no se relaciona con nadie no aporta a la solución porque nadie puede mandarle mensajes a sus instancias. Si sólo se comunican con otros objetos por parámetros se dibuja una flecha con línea punteada con la palabrita que parte del receptor del mensaje en cuestión y llega al objeto que se envía por parámetro.

    + + + +

    Especificar bien las relaciones, diferenciar la herencia de la asociación o conocimiento.
    +Si la flecha que se usa para los atributos tiene un triángulo en la punta o si la de herencia es una flecha simple está mal!

    + +

    La presentación del parcial

    + +

    Indicar cómo se usa lo que hicieron
    +Para cada punto del parcial, indicar qué mensaje hay que mandarle a qué objeto

    + + + +

    El orden del código es importante a la hora de entender la solución propuesta
    +Está bueno ordenarlo “punto por punto” (en contraposición a juntar todos los métodos de una misma clase). No solo facilita la corrección sino además los ayuda a no olvidarse de nada

    + +

    También está bueno ir “de lo general a lo particular”, es decir, comenzar por el mensaje que se llamaría desde el workspace y luego los que se llaman desde ahí, así sucesivamente hasta los mensajes más específicos.

    + + + +

    Prolijidad
    +Hagan buena letra, no amontonen todo, etc.

    + + + +

    No escribir muy apretado
    +Así hay lugar para hacer anotaciones y correcciones.

    + + + +

    Ortografía
    +Los docentes tenemos indicación explícita del departamento de desaprobar a quienes tengan muchos errores de ortografía, así que pilas con eso.

    + +

    De paso no estaría mal practicar un poquito de redacción, aunque eso va más que nada para el final.

    + +

    Otras cuestiones importantes

    + +

    ¡No devolver Strings para informar un error!
    +Los errores se informan con self error.

    + + + +

    Evitar repetición de código
    +En el caso general no está bien tener código repetido; esto suele indicar una falta de abstracción o bien un problema de asignación de responsabilidades.

    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/currificacion.html b/wiki/articles/currificacion.html new file mode 100644 index 0000000000..8c900c43b6 --- /dev/null +++ b/wiki/articles/currificacion.html @@ -0,0 +1,339 @@ + + + + + + + + + + + Currificacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Currificacion +

    +
    + + + +
    +

    Cuando hablamos de currificación nos referimos a que todas las funciones reciben un único parámetro como máximo. El hecho de que sea posible definir funciones de más de un parámetro se debe a que son funciones currificadas. Cuando evaluamos por ejemplo, max 4 5, lo que sucede es que se le aplica el número 5 a la función resultante de aplicarle el 4 a max, o sea que se transforma en (max 4) 5

    + +

    Por eso, cuando escribimos el tipo de una función no hay una distinción entre lo que son los parámetros y el valor de retorno, se desdibuja un poco la diferencia. Por ejemplo, el tipo de max puede escribirse de dos formas:

    +
    max :: (Ord a) => a -> a -> a --- Forma tradicional
    +
    +max :: (Ord a) => a -> (a -> a) --- Forma currificada
    +
    +

    La segunda denota que max es una función de 1 parámetro que retorna una función que espera y retorna algo del mismo tipo que lo que ella espera.

    + +

    Esto es lo que permite tener Aplicación Parcial

    + +

    Relacionando con Expresiones Lambda, cuando las funciones están currificadas, como pasa con todas las funciones en Haskell, podemos pensar como si hubiera alguien construyendo lambdas de un único parámetro al rededor de todas nuestras funciones para que las podamos usar como queremos por ejemplo:

    +
    funcion a b c = ... la lógica de tu función ...
    +
    +

    se traduce a:

    +
    (\p1 -> (\p2 -> (\p3 -> funcion p1 p2 p3) ) )
    +
    + +

    eso permite que al evaluar funcion parametro, lo que retorna sea una función que todavía puede ser aplicada 2 veces.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/data--definiendo-nuestros-tipos-en-haskell.html b/wiki/articles/data--definiendo-nuestros-tipos-en-haskell.html new file mode 100644 index 0000000000..c724000652 --- /dev/null +++ b/wiki/articles/data--definiendo-nuestros-tipos-en-haskell.html @@ -0,0 +1,951 @@ + + + + + + + + + + + Data definiendo nuestros tipos en haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Data definiendo nuestros tipos en haskell +

    +
    + + + +
    +

    Data: qué es y para qué sirve

    + +

    Usamos data para definir un nuevo tipo de dato, por ejemplo si quisiéramos definir el tipo Booleano escribiríamos

    + +
    +  data Booleano = <...> 
    +
    +
    + + + + + + + + +
    Qué vamos a escribir en <…>? los posibles valores que tiene ese tipo separados por un pipe ()
    + +
    +  data Booleano = Falso | Verdadero
    +
    +
    + +

    Con esta notación podríamos pensar que el tipo Int está escrito de la siguiente manera

    + +
    +  data Int = -2147483648 | -2147483647 | ... | -1 | 0 | 1 | 2 | ... | 2147483647  
    +
    +
    + +

    + Nota: Int no está definido de esta manera pero sirve para entender el uso de data +

    + +

    Si quisiéramos escribir el tipo ColorPrimario cuales serían sus posibles valores?

    + +
    +  data ColorPrimario = Rojo | Amarillo | Azul
    +
    +
    + +

    Si luego quisiéramos hacer una función combinar que reciba dos colores primarios distintos y me retorne un color secundario (Naranja, Violeta o Verde), podemos resolverlo usando pattern matching:

    + +
    +  data ColorSecundario = Naranja | Violeta | Verde 
    +
    +combinar :: ColorPrimario -> ColorPrimario -> ColorSecundario
    +combinar Rojo Amarillo = Naranja
    +combinar Amarillo Rojo = Naranja
    +combinar Rojo Azul = Violeta
    +combinar Azul Rojo = Violeta
    +combinar Amarillo Azul = Verde
    +combinar Azul Amarillo = Verde
    +
    +
    + +

    Cabe mencionar que esto mismo de los colores lo podríamos haber hecho con Strings, pero haberlo hecho con data limita los valores posibles a aquellas cosas que consideramos válidas para el tipo específico que queremos representar.

    + +

    Tuplas tuplas tuplas

    + +

    Una forma de representar valores que están compuestos por otros valores, tal que cada uno de ellos tiene una semántica distinta, es usando uno de los tipos compuestos bien conocidos de Haskell, las tuplas.

    + +

    Vamos a hacer un ejemplo con tuplas de 2 elementos por simplicidad, pero lo mismo se aplica para tuplas de n elementos. Supongamos que queremos armar un programa en el cual queremos representar un alumno por su nombre (un String) y sus notas (una lista de Int = [Int]) y también queremos representar una película por su título (unString) y los puntajes que le ponen los críticos en imdb (una lista de Int = [Int]). Por ejemplo:

    + +
    +  cursoK9 = [("Federico",[2,3]),("Líder",[10,10,10,10,10]),("Germain",[8,9,10])]
    +pelis = [("Pedornia", [0,0,-3,-666]),("Pulp Fiction", [9,10,9]),("Fight Club", [3,8,8,9,9,10])]
    +
    +
    + +

    Vamos a agregar además algunas funciones básicas para interactuar con alumnos y películas fácilmente:

    + +
    +  nombreAlumno unAlumno = fst unAlumno
    +notasAlumno unAlumno = snd unAlumno
    +tituloPelicula unaPelicula = fst unaPelicula
    +puntajesPelicula unaPelicula = snd unaPelicula
    +
    +
    + +

    Y una de las cosas que queremos hacer con los alumnos es saber si empezó mal (si su primer nota no está aprobada):

    + +
    +  empezoMal = not . aprobada . head . notasAlumno
    +aprobada nota = nota >= 6
    +
    +
    + +

    Si usamos lo que definimos arriba como un solo programa (un solo .hs), podemos ver que:

    + +
      +
    • La función nombreAlumno es igual a la función tituloPelicula
    • +
    • La función notasAlumno es igual a la función puntajesPelicula
    • +
    + +

    Nada me impide consultar:

    + +
    +  > puntajesPelicula ("Líder",[10,10,10,10,10])
    +[10,10,10,10,10]
    +
    +> empezoMal (head pelis)
    +True
    +
    +
    + +

    Todo esto es posible porque si miramos los tipos que infiere Haskell no existe diferencia entre una película y un alumno, para Haskell los alumnos y películas son sólo tuplas de 2 elementos. Ejemplo:

    + +
    +  > puntajesPelicula ([1,2,3],(True,"hola"))
    +(True,"hola")
    +
    +
    + +

    Si definimos un alias de tipo para Alumno y Pelicula de esta forma:

    +
    +  type Alumno = (String, [Int])
    +type Pelicula = (String, [Int])
    +
    +
    + +

    Y luego restringimos los tipos de todas las funciones para explicitar que lo que reciben son alumnos o películas según corresponda:

    +
    +  nombreAlumno :: Alumno -> String
    +nombreAlumno unAlumno = fst unAlumno
    +notasAlumno :: Alumno -> [Int]
    +notasAlumno unAlumno = snd unAlumno
    +
    +tituloPelicula :: Pelicula -> String
    +tituloPelicula unaPelicula = fst unaPelicula
    +puntajesPelicula :: Pelicula -> [Int]
    +puntajesPelicula unaPelicula = snd unaPelicula
    +
    +empezoMal :: Alumno -> Bool
    +empezoMal = not . aprobada . head . notasAlumno
    +
    +
    + +

    De lo único que nos salvamos es de consultas como:

    +
    +  > puntajesPelicula ([1,2,3],(True,"hola"))
    +
    +
    +

    Porque esa tupla contiene elementos de tipos que no coinciden con los explicitados. Pero esta otra consulta no se ve afectada por el cambio que realizamos, porque tanto Alumno como Pelicula no son más que (String, [Int]):

    +
    +  > empezoMal (head pelis)
    +True
    +
    +
    + +

    Ya que Haskell es un lenguaje “que se fija mucho en los tipos”, nos gustaría que un caso como los de arriba nos tirará error (donde en vez de mandar un alumno o una película según corresponda, enviamos cualquier otra cosa incluyendo un alumno donde se esperaba una película y visceversa).

    + +

    Definiendo nuevos tipos

    + +

    Para poder diferenciar a un alumno de una película y a ambos de una tupla, tenemos que definir un nuevo tipo. Eso se hace usando data:

    + +
    +  data NuevoTipo = Constructor Tipo1 Tipo2 ... Tipon
    +
    +
    + +

    + Nota: el tipo y el constructor pueden llamarse igual, usaremos nombres distintos a fines didácticos para remarcar en qué contextos lo que usamos es el constructor y en cuáles el tipo. +

    + +

    En nuestro ejemplo:

    + +
    +  data Alumno = UnAlumno String [Int]
    +data Pelicula = UnaPelicula String [Int]
    +
    +
    + +

    Ahora, para obtener un nuevo alumno o una nueva película, tenemos que usar el “Constructor”

    + +
    +  cursoK9 = [UnAlumno "Federico" [2,3], UnAlumno "Líder" [10,10,10,10,10], UnAlumno "Germain" [8,9,10]]
    +
    +
    + +
    +  -- No cambia
    +empezoMal unAlumno = 4 > head (notasAlumno unoAlumno)
    +
    +
    + +
    +  pelis = [UnaPelicula "Pedornia" [0,0,-3,-666], UnaPelicula "Pulp Fiction" [9,10,9], UnaPelicula "Fight Club" [8,8,8,9,9,10]]
    +
    +
    + +
    +  -- Ahora estas funciones usan Pattern-Matching!
    +nombreAlumno (UnAlumno nombre notas) = nombre 
    +notasAlumno (UnAlumno nombre notas) = notas
    +tituloPelicula (UnaPelicula nombre notas) = nombre
    +puntajesPelicula (UnaPelicula nombre notas) = notas
    +
    +
    + +

    Es importante remarcar que al hacer esto un alumno o una película YA NO ES UNA TUPLA

    + +
    +  fst :: (a,b) -> a
    +nombreAlumno :: Alumno -> String
    +tituloPelicula :: Pelicula -> String
    +snd :: (a,b) -> b
    +notasAlumno :: Alumno -> [Int]
    +puntajesPelicula :: Pelicula -> [Int]
    +
    +
    + +
    +  cursoK9 :: [ Alumno ]
    +empezoMal :: Alumno -> Bool
    +
    +
    + +
    +  pelis :: [ Pelicula ]
    +
    +
    + +

    Ejemplos:

    + +

    A partir de estos valores:

    +
    +  fede = UnAlumno "Federico" [2,3]
    +ger = UnAlumno "Germain" [8,9,10]
    +pulp = UnaPelicula "Pulp Fiction" [9,10,9]
    +
    +
    + +

    Veamos qué sucede al hacer algunas consultas sobre funciones que esperan tuplas, alumnos o películas.

    +
    +  > fst fede
    +Error (fst espera una tupla y fede es de tipo Alumno)
    +> nombreAlumno fede
    +"Federico"
    +> nombreAlumno pulp
    +Error (nombreAlumno espera algo de tipo Alumno y pulp es de tipo Pelicula)
    +> puntajesPelicula fede
    +Error (puntajesPelicula espera Pelicula y fede es de tipo Alumno)
    +> puntajesPelicula pulp
    +[9,10,9]
    +> empezoMal fede
    +True
    +> empezoMal (head pelis)
    +Error (empezoMal espera Alumno y el primer elemento de pelis es de tipo Pelicula)
    +
    +
    + +

    Derivar typeclasses

    + +

    Es muy común querer comparar por igualdad y mostrar por pantalla un valor que tiene un tipo definido por nosotros.

    + +
    +  > head cursoK9
    +Error (Alumno no tiene la restricción Show)
    +
    +
    + +

    Para que esto funcione deberíamos:

    + +
      +
    • Decir que Alumno es un tipo que pertenece a la restricción Show
    • +
    • Definir la función show para un Alumno
    • +
    + +

    En vez de hacer esto a mano (agregando una instancia de la typeclass como se explica más adelante), y gracias a que los elementos que forman un Alumno SI tienen la restricción Show, podemos hacer que el Alumno “derive” esa restricción

    + +
    +  --Lo único que hay que agregar es deriving (Show)
    +data Alumno = UnAlumno String [Int] deriving (Show)
    +
    +
    + +

    Con este agregado podemos hacer

    + +
    +  > head cursoK9
    +UnAlumno "Federico" [2,3]
    +
    +
    + +

    Ahora, si hacemos lo siguiente

    + +
    +  > fede == ger
    +Error (el Alumno no tiene la restricción Eq)
    +
    +
    + +

    También parece común querer preguntar si dos alumnos son iguales (o distintos), pasa lo mismo que con Show, nos gustaría que el Alumno pertenezca a la typeclass Eq.

    + +
    +  --Lo único que hay que agregar es deriving (Show,Eq)
    +data Alumno = UnAlumno String [Int] deriving (Show,Eq)
    +
    +
    + +

    Con este agregado podemos hacer:

    + +
    +  > fede == ger
    +False
    +> UnAlumno "Roberto" [7,8,9] == UnAlumno "Huberto" [7,8,9]
    +False
    +> UnAlumno "Roberto" [7,8,9] == UnAlumno "Roberto" [7,8,9]
    +True
    +
    +
    + +

    También se puede utilizar el deriving con la clase Ord

    + +
    +  data Nota = Insuficiente | Regular | Bien | MuyBien
    +
    +
    + +

    Al hacer:

    + +
    +  Main> Insuficiente > Regular
    +ERROR: No instance for (Ord Nota)
    +
    +
    + +

    Esto se debe a que el tipo Nota no cumple con la restricción Ord, por defecto se considera a los valores en forma ascendente de izquierda a derecha (i.e. Insuficiente < Regular < Bien < MuyBien).

    + +

    Para obtener este comportamiento en los valores del tipo Nota lo único que debemos hacer es “derivar” la restricción Ord

    + +
    +  data Nota = Insuficiente | Regular | Bien | MuyBien deriving Ord
    +
    +
    + +
    +  Main> Insuficiente > Regular
    +False
    +
    +
    + +

    Lo mismo podría hacerse con los tipos ColorPrimario y ColorSecundario definidos anteriormente en este artículo. De seguro vamos a querer que puedan mostrarse. Con derivar Show para ColorSecundario sería suficiente para poder usar la función combinar :: ColorPrimario -> ColorPrimario -> ColorSecundario desde la consola y ver el resultado, pero a su vez poder ver los colores primarios suena como algo deseable.

    + +

    También podemos sacarle provecho a derivar Eq, lo que nos permitirá llegar a esta nueva solución sin repetición de lógica:

    +
    +  data ColorPrimario = Rojo | Amarillo | Azul deriving (Show, Eq)
    +data ColorSecundario = Naranja | Violeta | Verde deriving (Show, Eq)
    +
    +combinar :: ColorPrimario -> ColorPrimario -> ColorSecundario
    +combinar Rojo Amarillo = Naranja
    +combinar Rojo Azul = Violeta
    +combinar Amarillo Azul = Verde
    +combinar color1 color2 | color1 /= color2 = combinar color2 color1
    +
    +
    + +

    Data con Record Syntax

    + +

    Es muy común hacer funciones para obtener los valores que forman nuestro individuo compuesto como hicimos con las películas y los alumnos.

    + +

    Imaginen que ahora queremos agregarle a nuestro tipo Pelicula (además del nombre y sus puntajes), el nombre del director, el nombre de los actores principales y el año en que se estrenó.

    + +
    +  data Pelicula = UnaPelicula String String [String] Int [Int]
    +
    +
    + +

    Lo primero que notamos es que no es tan fácil identificar cada elemento. Para eso existe la posibilidad de declarar sinónimos de tipo usando type. En el ejemplo de las películas podemos hacer algo como:

    + +
    +  type Titulo = String
    +type NombreDirector = String
    +type Puntajes = [Int]
    +
    +data Pelicula = UnaPelicula Titulo NombreDirector [String] Int Puntajes deriving (Show,Eq)
    +
    +narnia = UnaPelicula "Pedornia" "Andrew Adamson" ["Tilda Swinton", "Georgie Henley","William Moseley"] 2005 [0,0,-3,-666]
    +pulp = UnaPelicula "Pulp Fiction" "Quentin Tarantino" ["John Travolta", "Uma Thurman", "Samuel L. Jackson"] 1994 [9,10,9]
    +fc = UnaPelicula "Fight Club" "David Fincher" ["Brad Pitt", "Edward Norton", "Helena Bonham Carter"] 1999 [8,8,8,9,9,10]
    +
    +
    + +

    Lo cual mejora un poco la expresividad de la definición. Igualmente a la hora de construir el dato tenemos que tener cuidado de no pasar primero el nombre del director y luego el título, porque al fin y al cabo los dos son de tipo String, y por ende va a tipar una construcción incorrecta en base a nuestro dominio.

    + +

    Otro tema es que tenemos que definir nuevamente funciones como tituloPelicula y puntajesPelicula:

    + +
    +  tituloPelicula (UnaPelicula nombre director actores anioEstreno notas ) = nombre
    +puntajesPelicula (UnaPelicula nombre director actores anioEstreno notas ) = notas
    +
    +
    + +

    Como en cualquier otro programa, las variables que no nos interesan en absoluto pueden ser reemplazadas por la variable anónima

    + +
    +  tituloPelicula (UnaPelicula nombre _ _ _ _ ) = nombre
    +puntajesPelicula (UnaPelicula _ _ _ _ notas ) = notas
    +
    +
    + +

    Lógicamente también tenemos que definir funciones para el resto de los campos que antes no existían:

    +
    +  directorPelicula (UnaPelicula _ director _ _ _ ) = director
    +actores (UnaPelicula _ _ actores _ _ ) = actores
    +anioEstreno (UnaPelicula _ _ _ anio _ ) = anio
    +
    +
    + +

    Una forma más rápida de definir este tipo de funciones es usando la sintaxis de registro (disponible en GHC, no en Hugs).

    + +

    En vez de definir sólo los tipos de los valores que van a estar en la película, también agregamos en la definición el nombre de la función por el cual queremos obtener dicho valor.

    + +

    Al utilizar la notación de registro hay que definir los campos que lo componen de una forma distinta, tenemos que:

    +
      +
    • encerrar la definición de los campos entre llaves { }
    • +
    • separar cada campo usando comas
    • +
    • indicar el nombre y de qué tipo es cada campo
    • +
    + +
    +  data Pelicula = 
    +  UnaPelicula
    +    {tituloPelicula :: String ,
    +    directorPelicula :: String,
    +    actores :: [String],
    +    anioEstreno :: Int,
    +    puntajesPelicula :: [Int]}
    +    deriving (Show,Eq)
    +
    +
    + +

    Con esta definición automaticamente Haskell define por nosotros las funciones tituloPelicula, puntajesPelicula, directorPelicula, actores y anioEstreno. El dominio de cada una de estas funciones es Pelicula y retornan lo que corresponda en cada caso.

    + +

    Además cuando querramos obtener una nueva Película, podemos hacer

    + +
    +  pulp = UnaPelicula "Pulp Fiction" "Quentin Tarantino" ["John Travolta", "Uma Thurman", "Samuel L. Jackson"] 1994 [9,10,9]
    +
    +
    + +

    O bien podemos usar la siguiente notación que sólo es válida para datas definidos de esta forma. Como se puede ver, es más claro a que campo pertenece cada valor y no es necesario seguir un orden en los valores mientras se indique a que campo pertenece

    + +
    +  pulp = 
    +  UnaPelicula {
    +    tituloPelicula = "Pulp Fiction",
    +    directorPelicula = "Quentin Tarantino",
    +    anioEstreno = 1994,
    +    puntajesPelicula = [9,10,9],
    +    actores = ["John Travolta", "Uma Thurman", "Samuel L. Jackson"]}
    +
    +
    + +

    Esto ayuda mucho a la expresividad, pero también es más verboso. Uno tiene que evaluar cuándo vale la pena y cuándo no.

    + +

    Otra cosa simpática de definir el data con sintaxis de registro es que que si el tipo deriva la typeclass Show, lo que se imprima en la consola cuando la expresión evaluada retorna algo de nuestro tipo (Pelicula en este caso) será más fácil de entender, porque mostrará cada valor asociado al nombre del campo en vez de uno al lado del otro, independientemente de qué notación se use para crear la película en cuestión.

    + +

    Finalmente algo más que nos da esta forma de definir el data es un azúcar sintáctico para facilitar el copiado de datos, lo cual es particularmente útil para trabajar de forma inmutable. Las siguientes definiciones son equivalentes:

    +
    +  agregarPuntaje nuevoPuntaje (UnaPelicula titulo director anio puntajes actores)
    +  = UnaPelicula titulo director anio (nuevoPuntaje : puntajes) actores
    +  
    +agregarPuntaje' nuevoPuntaje pelicula = pelicula { puntajesPelicula = nuevoPuntaje : puntajesPelicula pelicula }
    +
    +
    + +

    En ambos casos lo que se está haciendo es crear una nueva película que tiene la misma información que la que se recibió por parámetro, excepto por los puntajes donde indicamos cuáles deberían ser los puntajes de la nueva película. De ninguna forma se modificarán los puntajes de pulp si consultamos agregarPuntaje' 10 pulp.

    + +

    + IMPORTANTE! Tengan en cuenta al usar este feature de copiado de ser cuidadosos y no abusar (al igual que no debería abusarse del pattern matching) porque un uso demasiado extendido atenta contra las abstracciones pequeñas y reutilizables. Funciones chiquitas y reutilizables matan sintaxis cheta. +

    + +

    Cómo instanciar una typeclass

    + +

    Ya dijimos que a cada restricción se la conoce como typeclass. A cada tipo que pertenece a una typeclass se le debe definir una instancia de la misma.

    + +

    Por ejemplo la clase Eq en algún lugar del Prelude (la biblioteca standard de Haskell) puede estar definida así:

    + +
    +  -- Esto ya viene con Haskell
    +class Eq a where
    +  (==), (/=) :: a -> a -> Bool
    +-- Las instancias de Eq deben definir al menos una de estas 2 operaciones
    +  (/=) x y =  not (x == y)
    +  (==) x y =  not (x /= y)
    +
    +
    + +

    Si decimos que el tipo Bool pertenece a la clase Eq escribimos

    + +
    +  -- Esto ya viene con Haskell
    +instance Eq Bool where
    +  (==) True True = True
    +  (==) False False = True
    +  (==) _ _ = False
    +
    +
    + +

    Otro ejemplo con la clase Ord

    + +
    +  -- Notar que a tiene la restricción Eq en la definición de la clase Ord a
    +class Eq a => Ord a where
    + (<) :: a -> a -> Bool
    + (<=) :: a -> a -> Bool
    + (>) :: a -> a -> Bool
    + (>=) :: a -> a -> Bool
    + max :: a -> a -> a
    + min :: a -> a -> a
    +
    +
    + +

    Si queremos hacer que el tipo Pelicula sea instancia de la clase Ord (por poner un ejemplo, definimos la función (>) para que nos diga que una película es mayor que otra si su promedio de puntajes es mayor), podemos escribir:

    + +
    +  instance Ord Pelicula where
    +  (>) unaPelicula otraPelicula = promedio (puntajesPelicula unaPelicula) > promedio (puntajesPelicula otraPelicula)
    +
    +
    + +

    Por lo general es suficiente con derivar typclasses en nuestros data, pero es importante recordar que para poder hacer esto, todos los componentes del data a su vez deben pertenecer al typeclass que estamos derivando. Y si en algún momento nos pasa que tenemos un data que se compone, entre otras cosas, por alguna función, ya no vamos a poder derivar así como así Show y Eq que son las más usuales, porque las funciones no son ni Show ni Eq.

    + +

    En esos casos podemos o bien optar porque nuestro data no sea Show o Eq, o bien definir un instance para esta typeclass que se corresponda con nuestro tipo de dato y así determinar nuestra propia solución a ese problema.

    + +

    Supongamos que queremos mostrar a nuestros alumnos de una forma distinta, que nos muestre el nombre, las notas y además nos diga el estado de cursada (si aprobó o no en base a sus notas). Necesitamos agregar un instance para Show Alumno en vez de derivar Show. Por ejemplo:

    + +
    +  instance Show Alumno where
    +  show (UnAlumno nombre notas) = show nombre ++ ": " ++ estadoDeCursada notas ++ " con " ++ show notas
    + 
    +estadoDeCursada notas
    +  | all aprobada notas = "CURSADA APROBADA"
    +  | otherwise = "CURSADA DESAPROBADA"
    +
    +
    + +

    Múltiples constructores por tipo

    + +

    Supongamos que nos interesa saber la densidad de un cuerpo. Por ahora vamos a manejar cilindros (de los cuales sabemos su masa, su altura y el radio de su base), cubos (sólo conocemos su masa y el largo de alguno de sus lados) y esferas (de ellas se conoce su masa y su radio).

    + +

    Para calcular la densidad de un cuerpo vamos a utilizar la siguiente fórmula: densidad = masa / volumen.

    + +

    Arranquemos por declarar el tipo de dato para representar un cuerpo:

    + +
    +  
    +data Cuerpo =
    + Cilindro
    +   {masa :: Float,
    +   altura :: Float,
    +   radio :: Float} |
    + Cubo
    +   {masa :: Float,
    +   lado :: Float} |
    + Esfera
    +   {masa :: Float,
    +   radio :: Float}
    + deriving (Show,Eq)
    +
    +
    + +

    Podemos ver que el tipo Cuerpo incluye los constructores Cilindro, Cubo y Esfera. Como la fórmula de la densidad es igual para todos los cuerpos podemos escribir:

    + +
    +  densidad unCuerpo = masa unCuerpo / volumen unCuerpo
    +
    +
    + +

    Ahora bien, el cálculo del volumen es algo particular para cada cuerpo

    + +
    +  volumen (Cilindro _ unaAltura unRadio) = pi * unRadio * unaAltura
    +volumen (Cubo _ unLado) = unLado ** 3
    +volumen (Esfera _ unRadio) = 4/3 * pi * (unRadio ** 3)
    +
    +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/declaratividad-vs--expresividad.html b/wiki/articles/declaratividad-vs--expresividad.html new file mode 100644 index 0000000000..f1c65b3742 --- /dev/null +++ b/wiki/articles/declaratividad-vs--expresividad.html @@ -0,0 +1,441 @@ + + + + + + + + + + + Declaratividad vs expresividad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Declaratividad vs expresividad +

    +
    + + + +
    +

    Muchas veces mencionamos los conceptos de Declaratividad y Expresividad, pero ¿cuando corresponde hablar de uno o del otro? ¿Y como se relacionan con otros conceptos vistos en la materia? Veamoslo con algunos ejemplos:

    + +

    “sumar una lista de números ns”

    + +
      +
    • Solución 1 (utiliza el concepto de orden superior):
    • +
    + +

        foldl (+) 0 ns

    + +
      +
    • Solución 2 (no utiliza el concepto de orden superior):
    • +
    + +

        sum ns

    + +

    La solución 2 es más declarativa que la solución 1 ya que en la solución 1 hay que saber:

    + +

    que se suma con la función (+)

    + +

    cómo se define el valor inicial del acumulador (0)

    + +

    En la solución 2 estos detalles no existen

    + +

    Entonces:

    + +
      +
    • Siempre que se hable de más o menos declarativo comparen cosas, no digan más declarativo al aire
    • +
    • Una solución A es más declarativa que una solución B si:
    • +
    + +
      +
    1. +

      A tiene menos detalles algorítmicos que B

      +
    2. +
    3. +

      Esto significa que la noción de algorítmo/secuencia de pasos/definición del “cómo lo hace” sea menor en A que en B

      +
    4. +
    + +

    Así como pasa con orden superior y declaratividad, pasa con la idea de polimorfismo y declaratividad.

    + +

    Otra cualidad que remarcamos en las soluciones es la expresividad, decimos que una solución A es más expresiva que una solución B si la solución A se entiende más rápido/es más fácil de leer que la solución B.

    + +

    Claramente la idea de expresividad puede verse de forma subjetiva.

    + +

    Volviendo a las soluciones para sumar una lista de números

    + +
      +
    • Solución 3
    • +
    + +

      sumar [] = 0 +  sumar (x:xs) = x + sumar xs

    + +

    Alguien puede decir que la solución 1 es más expresiva que la solución 2 (porque le gusta el foldl y lo entiende) pero en la primer clase de funcional si te muestran (sin explicar) entre la solución 1 y la solución 2 es muy probable que la solución 2 pasaría a ser la más expresiva. En contraste, para alguna persona retorcida la solución 3 puede ser la más expresiva ….

    + +

    A lo que vamos con esto es que, la idea de declaratividad debería ser más objetiva que la idea de expresividad.

    + +

    De todas formas, con la debida justificación y relacionándolo con el ejercicio del final, se puede hablar de ambos conceptos. Por lo general, las soluciones más declarativas resultan a su vez más expresivas, pero dejando las subjetividades a un lado, un código imperativo bien hecho puede resultar más legible que uno declarativo con nombres de operaciones y variables mal puestos.

    + +

    Declaratividad, expresividad y abstracción

    + +

    Es importante no confundir los términos de expresividad, abstracción y declaratividad. Aunque están muy relacionados entre sí, son tres conceptos diferentes, que bien pueden darse por separado.

    + +

    Como decíamos antes, la relación que con más frecuencia vamos a encontrar es que un código declarativo tiende a ser más expresivo que uno imperativo, ya que puedo leer directamente de qué se trata el problema, en lugar de deducir qué es lo que un algoritmo está tratando de resolver.

    + +

    Ejemplo en pseudocódigo:

    + +

    Integer cuantosPares(Array ns){ + Integer i; + Integer acum = 0; +  for(i = 0 ; i < longitudDelArray(ns) ; i = i + 1){ +   if (ns[i] mod 2 == 0) { +    acum = acum + 1; +   } +  } + return acum; +}

    + +

    Esta función de por sí representa una abstracción: es una operación que puedo utilizar cada vez que necesite saber la cantidad de números pares hay en el array que se recibe por parámetro. Gracias a que tiene un nombre apropiado (detalle que aumenta la expresividad), podría no tener que leer el código para saber qué es lo que hace.

    + +

    Leyendo el cuerpo de la función, podemos tratar de encontrar otra abstracción más. En el contexto de la función cuantosPares, ¿qué significa este fragmento?

    + +

    if (ns[i] mod 2 == 0) { + acum = acum + 1; +}

    + +

    Podemos entender que se está evaluando si ns[i] (el elemento del array que está en la posición i) es múltiplo de 2, y si esto es cierto contamos un par más. Una abstracción podría ser una función que evalúe si un número (en este caso ns[i]) es múltiplo de otro (en este caso 2). El código cambiaría a:

    + +

    if(esMultiploDe(ns[i],2)) { + acum = acum + 1; +}

    + +

    Al encontrar una abstracción y ponerle nombre, hace que mi código quede más expresivo. Pero recordemos que hacíamos esto para saber si ns[i] era par. Cuando evaluamos la función esMultiploDe con 2 como segundo argumento, estamos justamente preguntando si ns[i] es par.

    + +

    Teniendo en cuenta esto, podríamos tener directamente la abstracción esPar, i.e. una función que recibe un solo argumento (un número) y me dice si ese número es par o no. Por otro lado, si estamos contando pares, la variable acum bien podría llamarse cantidadDePares. Entonces el código podría quedar así:

    + +

    if(esPar(ns[i])) { + cantidadDePares = cantidadDePares + 1; +}

    + +

    Podemos ver que un componente esencial de la expresividad puede ser el elegir buenos nombres para los elementos de mi código (variables, funciones, procedimientos, etc).

    + +

    Haber encontrado estas abstracciones ayudó a que el código quede más expresivo, ya que una se entiende más rápido lo que hace esPar(ns[i]) en comparación con esMultiploDe(ns[i],2) o con ns[i] mod 2 == 0.

    + +

    Ahora el código expresa que un número tiene que ser par en vez de exponer el algoritmo o las operaciones matemáticas necesarias para saber si el módulo de la división por 2 es 0. Esta última solución está más cerca de qué quiero resolver en vez de cómo pretendo resolverlo.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/declaratividad.html b/wiki/articles/declaratividad.html new file mode 100644 index 0000000000..bab071c857 --- /dev/null +++ b/wiki/articles/declaratividad.html @@ -0,0 +1,416 @@ + + + + + + + + + + + Declaratividad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Declaratividad +

    +
    + + + +
    +

    La declaratividad es una característica de algunas herramientas que permiten o fuerzan la separación entre el conocimiento del dominio de un programa y la manipulación de dicho conocimiento. Dichas herramientas pueden ser de diversa naturaleza, tanto prácticas como lenguajes, entornos, frameworks, etc o conceptuales como paradigmas o arquitecturas.

    + +

    El concepto de declaratividad se contrapone a la tradicional programación imperativa en la cual el conocimiento y la lógica se encuentran muchas veces mezclados dentro de la misma porción de código resultando difícil determinar donde comienza uno y dónde termina el otro.

    + +

    Las herramientas declarativas permiten muchas veces un más alto grado de reutilización y de abstracción en tareas repetitivas y por eso la declaratividad es hoy en día una característica fundamental en muchos entornos de programación para sistemas de mediana o gran envergadura, ya que es una herrramienta importante para organizar y simplificar la construcción de un sistema complejo.

    + +

    Conocimiento y manipulación

    + +

    En un programa construido de forma declarativa se produce una separación entre la descripción del problema por un lado y los algoritmos o estrategias para encontrar la solución por el otro.

    + +

    Un error común es hablar de la separación entre el qué y el cómo. Si bien esta idea puede servir como una primera aproximación al concepto, en realidad cualquier función - predicado - método - procedimiento puede verse como una separación entre el qué (dado por el nombre de la función, lo único que necesita saber el invocador) y el cómo (la implementación de la función).

    + +

    En un programa imperativo suelen estar mezcladas la descripción del problema con la estrategia de resolución, a tal punto que muchas veces es difícil de detectar cuál es el problema que se está tratando de solucionar.

    + +

    Para verlo mejor es conveniente bajar a un ejemplo, para eso vamos a pensar en el sistema de correlatividades de la facultad. Pensando imperativamente, el algoritmo de solución sería algo así:

    + +
      +
    1. A partir de un alumno obtener la carrera que está cursando y con eso las materias de esa carrera, almacenarlas en una variable auxiliar.
    2. +
    3. Eliminar de esa colección de materias aquellas que el alumno ya haya cursado.
    4. +
    5. Recorrer la lista de las materias restantes y para cada una: +
        +
      1. Obtener su lista de corelativas
      2. +
      3. Recorrerla y para cada correlativa verificar si el alumno cursó esa materia
      4. +
      5. En caso de no haberla cursado, eliminar la materia de la colección auxiliar
      6. +
      +
    6. +
    7. Las materias que quedaron en la colección son las que se pueden cursar.
    8. +
    + +

    En cambio, la definición declarativa eliminará todos los conceptos programáticos como variables auxiliares, recorrer colecciones o ir eliminando elementos de la colección. Más aún, la versión declarativa no tendrá un concepto de orden, simplemente intentará describir el problema de la forma más abstracta posible, solamente tratando de contestar la pregunta, ¿qué materias puede cursar un alumno?

    + +
      +
    1. Un alumno puede cursar las materias de su carrera que no haya cursado aún y cuyas correlativas sí haya cursado.
    2. +
    + +

    En este punto seguramente se preguntarán si es posible hacer un programa que exprese solamente eso, sin toda la lógica adicional necesaria, bueno aquí está el código prolog que dice exactamente eso:

    + +
        puedeCursar(Alumno, Materia):-
    +      carrera(Alumno, Carrera), materia(Carrera, Materia),       % Es una materia de la carrera del alumno
    +      not(curso(Alumno, Materia)),                               % No cursó la materia
    +      forall(correlativa(Materia, Corr), curso(Alumno, Corr)).   % Cursó todas las correlativas
    +
    + +

    Elementos en un programa declarativo

    + +

    Un programa declarativo separa claramente los siguientes elementos:

    + +
      +
    • El objetivo
    • +
    • El conocimiento
    • +
    • El motor que manipula el conocimiento para lograr el objetivo deseado
    • +
    + +

    En el ejemplo anterior, el objetivo es la consulta realizada sobre qué materias puede cursar un alumno. El conocimiento es la información que se encuentra en la base de conocimiento sobre las materias disponibles en la carrera y cuáles ya cursó el alumno en cuestión. El motor de Prolog toma el conocimiento y resuelve la consulta realizada en base al programa y deduce todas las posibles relaciones que la satisfagan.

    + +

    El mecanismo utilizado por el motor de Prolog llamado Backtracking prueba todas las posibilidades para solucionar el problema, no hace falta programar este algoritmo para cada problema particular, con lo cual podemos concentrarnos exclusivamente en el objetivo de nuestro programa y no en la complejidad algorítmica general que permite procesar la información.

    + +

    Declaratividad en los distintos paradigmas

    + +

    Dentro de los paradigmas vistos, el paradigma funcional y el lógico tienen una naturaleza declarativa. Eso no quiere decir que no se pueda ser declarativo programando bajo el marco de otro paradigma, de la misma forma en que se puede programar de forma poco declarativa en lógico y funcional (por ejemplo, la recursividad no es una herramienta muy declarativa que digamos).

    + +

    A medida que logramos abstraer nuestros problemas podemos armar nuestros propios motores que nos permitan trabajar de forma más declarativa.

    + +

    Herramientas declarativas en el mundo real

    + +

    El lenguaje SQL para trabajar con bases de datos relacionales es un claro ejemplo de declaratividad que se usa ampliamente en la indusria.

    + +

    Los motores de bases de datos, a partir de consultas provistas por el usuario que especifican el origen de los datos (FROM), los filtros a aplicar sobre los posibles resultados (WHERE), las transformaciones a realizar sobre las filas resultantes (SELECT) y criterios de ordenamiento (ORDER BY) por ejemplo, realizan búsquedas complejas relacionando las tablas de origen solicitadas de la forma más optimizada posible en base a los índices que el usuario defina y estadísticas que el mismo motor realiza.

    + +

    El algoritmo utilizado por el motor está muy separado del conocimiento (qué entidades existen, cómo se relacionan entre ellas), lo cual permite al usuario abstraerse de esta lógica de búsqueda y concentrarse exclusivamente en el modelado de datos.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/definiciones-locales--where-.html b/wiki/articles/definiciones-locales--where-.html new file mode 100644 index 0000000000..837efce972 --- /dev/null +++ b/wiki/articles/definiciones-locales--where-.html @@ -0,0 +1,340 @@ + + + + + + + + + + + Definiciones locales where + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Definiciones locales where +

    +
    + + + +
    +

    Hay ocasiones en las cuales nuestras funciones tienen una complejidad que puede disminuirse definiendo funciones más chicas que la componen, pero las mismas no son de particular interés fuera del contexto de esa función. Una forma de definir funciones que sólo se encuentran definidas en el contexto de una función es usando where.

    + +

    Supongamos que queremos hacer una función que nos dice el estado de gordura de una persona y sabemos que esto se determina a partir de la altura y el peso de la misma

    + +
    gordura peso altura
    +  | peso / altura ^ 2 <= 18.5 = "Desnutrido"  
    +  | peso / altura ^ 2 <= 25.0 = "Normal"  
    +  | peso / altura ^ 2 <= 30.0 = "Gordito"  
    +  | otherwise                 = "Obeso"  
    +
    + +

    Podemos ver que la expresión peso / altura ^ 2 se repite y sería bueno extraerlo a una función, pero para el resto del programa del médico clínico no tiene ninguna utilidad. Una forma elegante para definir la función gordura es mediante definiciones locales dándole un nombre a esta expresión.

    + +
    gordura peso altura
    +  | indiceGordura <= 18.5 = "Desnutrido"  
    +  | indiceGordura <= 25.0 = "Normal"  
    +  | indiceGordura <= 30.0 = "Gordito"  
    +  | otherwise             = "Obeso"  
    +     where indiceGordura = peso / altura ^ 2
    +
    + +

    Algo simpático, como se ve en este ejemplo, es que podemos usar los argumentos de la función global en la local como si fueran constantes. Si quisiéramos poder variar los valores también es posible parametrizar a la función local como cualquier otra función.

    + +
    holaDones don1 don2 = saludar don1 ++ saludar don2
    +   where saludar alguien = "Hola Don " ++ alguien ++ "! "
    +
    + +

    Nota: Al igual que con las guardas, para que el where funcione hay que dejar al menos un espacio de indentación

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/deploy-en-maven-central.html b/wiki/articles/deploy-en-maven-central.html new file mode 100644 index 0000000000..2e71e1e89f --- /dev/null +++ b/wiki/articles/deploy-en-maven-central.html @@ -0,0 +1,478 @@ + + + + + + + + + + + Deploy en maven central + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Deploy en maven central +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Estás desarrollando un proyecto Maven para Uqbar -el cual tiene como pom padre uqbar-parent-project- y ahora lo querés desplegar en Maven Central, ¿que hacer?

    + +

    Tenemos 2 tareas para hacer: preparar el release y luego publicarlo. La primera sí o sí vas a tener que hacerla en tu PC, porque vos sos responsable de, por ejemplo, elegir la versión de este nuevo release. Veamos entonces cómo hacer esto:

    + +

    Preparar el release

    + +
      +
    1. Creamos el release
    2. +
    + +
    +
    +
    +      mvn --batch-mode release:clean release:prepare
    +
    +    
    +
    +
    + +

    Este comando crea un commit y un tag para la nueva versión y luego otro commit agregandole nuevamente el -SNAPSHOT a la versión. La opción –batch-mode hace que el plugin no pregunte la versión y asuma la correlativa a la actual, puede omitirse si se quiere especificar otra versión (siempre siguiendo los lineamientos planteados por Semantic Versioning).

    + +
      +
    1. Verificamos que todo esté bien
    2. +
    + +
    +
    +
    +      git log # deberia haber dos commits nuevos
    +git tag -l # deberia haber un tag nuevo
    +git status # no debería quedar nada sin commitear
    +
    +    
    +
    +
    + +

    Si quedaron cambios sin commitear podés agregarlos al último commit

    + +
    +
    +
    +      git commit --amend --no-edit
    +
    +    
    +
    +
    + +
      +
    1. Pusheamos los 2 commits nuevos y el tag
    2. +
    + +
    +
    +
    +      git push --follow-tags
    +
    +    
    +
    +
    + +

    Y con esto ya tendremos en nuestro repositorio GitHub todo lo necesario para publicar el nuevo release.

    + +

    Publicar el release

    + +

    Este punto va a depender de cómo esté configurado el repositorio. Si bien configurada la integración continua via Travis, entonces no tenés que hacer más nada. Por las dudas, entrá a Travis y fijate que se esté buildeando el tag que acabás de subir (esto podés verlo en la parte de Branches).

    + +

    Si no tiene configurado Travis, entonces tenés dos opciones:

    + +
      +
    • +

      Configurarlo vos :). No es difícil y tenemos una guía de cómo hacerlo en el blog de Uqbar (próximamente…).

      +
    • +
    • +

      Hacerlo a mano. Tené en cuenta que para esto tenés que tener una cuenta en Sonatype autorizada para subir artefactos de Uqbar y toda la configuración necesaria para que funcione (firma GPG publicada - hay un paso a paso en esta pregunta de Stack Overflow, credenciales en el settings.xml, etc), lo cual te va a llevar más tiempo que configurar el CI.

      +
    • +
    + +

    Si igualmente querés hacerlo, los pasos son estos:

    + +
      +
    1. Nos paramos en el tag que acabamos de crear
    2. +
    + +
    +
    +
    +      git checkout [nombre del release, por ejemplo v3.3]
    +
    +    
    +
    +
    + +
      +
    1. Publicamos el release en Sonatype
    2. +
    + +
    +
    +
    +      mvn clean deploy -Prelease # {poner la pwd de OSS: }
    +
    +    
    +
    +
    + +
      +
    1. (Opcional) Volvemos a master para seguir trabajando
    2. +
    + +
    +
    +
    +      git checkout master
    +
    +    
    +
    +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/deploys-componentes-de-dominio-uqbar.html b/wiki/articles/deploys-componentes-de-dominio-uqbar.html new file mode 100644 index 0000000000..c1b053803f --- /dev/null +++ b/wiki/articles/deploys-componentes-de-dominio-uqbar.html @@ -0,0 +1,414 @@ + + + + + + + + + + + Deploy componentes Uqbar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Deploy componentes Uqbar +

    +
    + + + +
    +

    Componentes de dominio Uqbar

    + +

    Motivación

    + +

    Los componentes de dominio uqbar están pensados para

    + +
      +
    • trabajar exclusivamente el modelo de negocio de los ejemplos…
    • +
    • … y poder reutilizarlos en diferentes tecnologías, ya sea de UI (Arena, Wicket, incluso Android) o de lenguajes base (podríamos definir el conversor en Java y generar la UI en Arena programándola en Scala, Xtend o Groovy)
    • +
    + +

    Configuraciones de Maven necesarias

    + +

    Parent-project

    + +

    El proyecto padre debe ser

    + +
      +
    • uqbar-examples-parent/ para proyectos Java
    • +
    • uqbar-examples-xtend-parent/ para proyectos Xtend
    • +
    + +

    Cualquiera de estos proyectos padre están deployados en el repositorio Maven de Uqbar, que está situado en

    + +

    http://uqbar-wiki.org/mvn/releases

    + +

    Dependencias

    + +

    En el pom debemos tener dependencias hacia

    + +
      +
    • uqbar-domain (la versión correspondiente)
    • +
    + +

    y no es necesario nada más.

    + +

    Los objetos de dominio deben anotarse como Observable para que funcionen en Arena, y respetar la convención Java Bean de tener un constructor vacío y getters/setters.

    + +

    Repositorios

    + +

    Dado que el proyecto padre no está en Maven Central, debemos agregar los repositorios maven de Uqbar en forma manual:

    + +
    +
    +
    +      	<repositories>
    +		<repository>
    +			<id>uqbar-wiki.org-releases</id>
    +			<name>uqbar-wiki.org-releases</name>
    +			<url>http://uqbar-wiki.org/mvn/releases</url>
    +		</repository>
    +		<repository>
    +			<snapshots />
    +			<id>uqbar-wiki.org-snapshots</id>
    +			<name>uqbar-wiki.org-snapshots</name>
    +			<url>http://uqbar-wiki.org/mvn/snapshots</url>
    +		</repository>
    +	</repositories>
    +
    +    
    +
    +
    + +

    Esto es para que el build de travis no falle.

    + +

    Deploy de una nueva versión

    + +

    Dado que no tenemos CI en este tipo de ejemplos, debemos manualmente

    + +
      +
    • Definir la versión del ejemplo, por caso el conversor podría pasar de 1.0.5-SNAPSHOT a 1.0.5
    • +
    • Hacer un commit + push al repositorio git
    • +
    • Una vez que esté el ok de Travis…
    • +
    • …en la línea de comando ejecutar
    • +
    + +
    +
    +
    +      $ mvn clean deploy
    +
    +    
    +
    +
    + +
      +
    • Esto agregará el componente en http://uqbar-wiki.org/mvn/releases.
    • +
    • Por último, conviene subir la versión del ejemplo a 1.0.6-SNAPSHOT, para estar seguros de no subir un release.
    • +
    + +

    A futuro esperamos contar con un esquema de CI que facilite las cosas.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/desafio--construir-esta-sucesion.html b/wiki/articles/desafio--construir-esta-sucesion.html new file mode 100644 index 0000000000..25bbf44cdc --- /dev/null +++ b/wiki/articles/desafio--construir-esta-sucesion.html @@ -0,0 +1,302 @@ + + + + + + + + + + + Desafio Construir esta sucesión + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Desafio Construir esta sucesión +

    +
    + + + +
    +

    Utilizando recursividad en Haskell, obtener la siguiente secuencia:

    + +
    1
    +11
    +21
    +1211
    +111221
    +312211
    +etc...
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/desafio--find-con-notacion-point-free.html b/wiki/articles/desafio--find-con-notacion-point-free.html new file mode 100644 index 0000000000..b4df09a20d --- /dev/null +++ b/wiki/articles/desafio--find-con-notacion-point-free.html @@ -0,0 +1,331 @@ + + + + + + + + + + + Desafio find con notacion point free + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Desafio find con notacion point free +

    +
    + + + +
    +

    Se desea definir la función find, que dado un criterio y una lista encuentra al primero que lo cumple:

    + +
    Main> find even [1,35,36,9]
    +36
    +
    + +

    El objetivo es definirla así:

    + +
    find = .........
    +
    + +

    O sea,

    + +
      +
    • con notación point-free para ambos parámetros,
    • +
    • sin usar expresiones lambda ni funciones auxiliares.
    • +
    + +

    Como la solución puede obtenerse probando un poco, para que la respuesta al desafío sea aceptada, debe ir acompañada de una pequeña explicación de cómo funciona.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/desafio--hacer-que-un-data-propio-sea-enum.html b/wiki/articles/desafio--hacer-que-un-data-propio-sea-enum.html new file mode 100644 index 0000000000..3d9e879da3 --- /dev/null +++ b/wiki/articles/desafio--hacer-que-un-data-propio-sea-enum.html @@ -0,0 +1,327 @@ + + + + + + + + + + + Desafio hacer que un data propio sea enum + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Desafio hacer que un data propio sea enum +

    +
    + + + +
    +

    Hacer que estas consultas funcionen exactamente así:

    + +
    Main> [CPersona "a" 1 .. CPersona "c" 1]
    +[CPersona "a" 1, CPersona "b" 1, CPersona "c" 1]
    +Main> [CPersona "f" 1 .. CPersona "k" 1]
    +[CPersona "f" 1, CPersona "g" 1, CPersona "h" 1, CPersona "i" 1, CPersona "j" 1, CPersona "k" 1]
    +
    +

    Pistas:

    + +
      +
    • Hay que hacer que el tipo Persona pertenezca a la clase Enum.
    • +
    • Para ello hay que usar la instrucción “instance” y definir dos funciones.
    • +
    • Acá hay un ejemplo de cómo están definidos los tipos básicos y sus typeclasses.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/desafio--ordenar-con-arbol-b.html b/wiki/articles/desafio--ordenar-con-arbol-b.html new file mode 100644 index 0000000000..8b8381fb55 --- /dev/null +++ b/wiki/articles/desafio--ordenar-con-arbol-b.html @@ -0,0 +1,287 @@ + + + + + + + + + + + Desafio ordenar con árbol B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Desafio ordenar con árbol B +

    +
    + + + +
    +

    Implementar en Haskell un árbol binario y utilizarlo para ordenar una lista

    + +

    Pista: ver ejemplo en ejemplo data multiples constructores.hs

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/desafio--piramide-de-numeros.html b/wiki/articles/desafio--piramide-de-numeros.html new file mode 100644 index 0000000000..4cecf76a56 --- /dev/null +++ b/wiki/articles/desafio--piramide-de-numeros.html @@ -0,0 +1,304 @@ + + + + + + + + + + + Desafio pirámide de números + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Desafio pirámide de números +

    +
    + + + +
    +

    Dada la siguiente pirámide (cortada) con 9 casilleros (5 en la base + 4 en la cima):

    + +

    Selection_010

    + +

    Se quieren acomodar los números del 1 al 9 donde cada casillero de la cima sea igual a la suma de los 2 casilleros que tiene como base. +Un ejemplo chiquito podría ser:

    + +

    Selection_012

    + +

    El desafío consiste en encontrar todas las soluciones posibles para acomodar los números del 1 al 9 en la pirámide.

    + +

    Ayuda: Existe el predicado between(Inicio, Fin, Numero) el cual dado un número Inicio y un número Fin relaciona algún Numero que se encuentra entre esos otros dos.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/desafio--suma-de-distancias.html b/wiki/articles/desafio--suma-de-distancias.html new file mode 100644 index 0000000000..a626652666 --- /dev/null +++ b/wiki/articles/desafio--suma-de-distancias.html @@ -0,0 +1,316 @@ + + + + + + + + + + + Desafio suma de distancias + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Desafio suma de distancias +

    +
    + + + +
    +

    Parte 1

    + +

    Escribir el código necesario (en donde sea necesario) para poder ejecutar en un workspace:

    + +

    1 kilometros + 20 metros

    + +

    y que al imprimir (print it) el resultado, se obtenga:

    + +

    1020 metros

    + +

    Claramente debe funcionar también para otros números que no sean el 1 y el 20.

    + +

    Parte 2

    + +

    Hacer que funcione cualquier combinación:

    + +

    3 metros + 400 metros + 2 kilometros +"al imprimirlo imprime 2403 metros"

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/desafio--suma-par.html b/wiki/articles/desafio--suma-par.html new file mode 100644 index 0000000000..e0c599a1b5 --- /dev/null +++ b/wiki/articles/desafio--suma-par.html @@ -0,0 +1,300 @@ + + + + + + + + + + + Desafio Suma Par + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Desafio Suma Par +

    +
    + + + +
    +
    sumaPar :: Number -> Number -> Bool
    +sumaPar = f.(+)
    +
    + +
      +
    1. Definir f para que la función diga si la suma de dos números da un número par.
    2. +
    3. Explicar el tipo de f y por qué se puede componer con la función (+).
    4. +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/desafio--triada-uqbariana.html b/wiki/articles/desafio--triada-uqbariana.html new file mode 100644 index 0000000000..7aea38b62e --- /dev/null +++ b/wiki/articles/desafio--triada-uqbariana.html @@ -0,0 +1,376 @@ + + + + + + + + + + + Desafio triada uqbariana + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Desafio triada uqbariana +

    +
    + + + +
    +

    Llamamos “triada” a cualquier conjunto de 3 números { x; y; z }. En particular nos enfocaremos en las triadas uniformes que son cualquier conjunto de 3 números iguales { x; x; x }.

    + +

    Decimos que una triada se aparenta a un número N si existe alguna forma de operar los tres números de la triada de modo que el resultado sea N. +Por ejemplo,

    +
      +
    • la triada { 2; 2; 2 } se aparenta al 3 porque 2 + 2 / 2 = 3
    • +
    • la triada { 1; 1; 1 } se aparenta al 2 porque (1 + 1) * 1 = 2
    • +
    + +

    Las restricciones para operar la triada son:

    +
      +
    1. No se permite agregar más números
    2. +
    3. Solamente usaremos las operaciones básicas: { +; -; *; /; }, ninguna más
    4. +
    + +

    Por último, definiremos las triadas uqbarianas como todas las triadas uniformes que van del 1 al 9, o sea:

    +
    { 1; 1; 1 }
    +{ 2; 2; 2 }
    +{ 3; 3; 3 }
    +{ 4; 4; 4 }
    +{ 5; 5; 5 }
    +{ 6; 6; 6 }
    +{ 7; 7; 7 }
    +{ 8; 8; 8 }
    +{ 9; 9; 9 }
    +
    + +

    Parte 1

    + +

    La primera parte del desafío consiste en encontrar algún número uqbariano, sabiendo que éste

    +
      +
    • Es un número entero positivo, y
    • +
    • Se aparenta con todas las triadas uqbarianas
    • +
    + +

    Se deberá indicar cuál es el número uqbariano y dar algún ejemplo de cómo se aparenta con cada triada uqbariana.

    + +

    Parte 2

    + +

    Así como existen las triadas, también existen los cuartetos, que son conjuntos de cuatro números. Y análogamente existen los cuartetos uqbarianos que son todos los cuartetos uniformes que van del 1 al 9.

    + +

    Indicar todos los números uqbarianos para los cuartetos.

    + +

    Parte 3

    + +

    Todos estos conjuntos se agrupan dentro de lo que llamamos familias, que se identifican con un rango siendo éste la cantidad de elementos dentro de un conjunto. Así, por ejemplo:

    +
      +
    • La familia uqbariana de rango 3 es equivalente a las triadas uqbarianas.
    • +
    • La familia uqbariana de rango 4 es equivalente a los cuartetos uqbarianos.
    • +
    + +

    Además, decimos que una familia es compacta cuando se aparenta con todos los números del 1 al 9.

    + +

    Determinar cuál es el rango de la primera familia uqbariana compacta.

    + +

    Parte BONUS

    + +

    Este ejercicio fue inspirado en el problema de este video.

    + +

    Para llegar a sus mismos resultados deberíamos agregar al programa las operaciones: raíz cuadrada y factorial.

    + +
    +

    Ayudas

    + +
      +
    1. En Prolog las operaciones matemáticas ¡son functores! Así que podemos relacionarlas como cualquier otro individuo. Por ej: +
      areaCirculo(Radio, pi * Radio ^ 2). % Se relaciona un radio con la FÓRMULA del área
      +
      +

      Se puede hacer la consulta

      +
      ?- areaCirculo(2, Formula), Area is Formula.
      +Formula = pi*2^2,
      +Area = 12.566370614359172.
      +
      +
    2. +
    3. OJO con Integers vs Floats, porque no son iguales: +
      ?- 0.0 is 1 - 1.
      +false.
      +
      +

      Tal vez quieras comparar todos los resultados con su representación flotante:

      +
      ?- 0.0 is float(1 - 1).
      +true.
      +
      +
    4. +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/desafios-cafe-con-leche.html b/wiki/articles/desafios-cafe-con-leche.html new file mode 100644 index 0000000000..3462e9b030 --- /dev/null +++ b/wiki/articles/desafios-cafe-con-leche.html @@ -0,0 +1,359 @@ + + + + + + + + + + + Desafios cafe con leche + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Desafios cafe con leche +

    +
    + + + +
    +

    En muchos cursos de docentes Uqbar se acostumbra dejar “desafíos café con leche” semanales, que consisten en resolver un problema para el cual hay que comprender a fondo los conceptos vistos en clase, y quizás agregar algo de investigación extra. Generalmente el docente ofrece un café con leche como premio al primero que lo resuelve. Aquí se detallan algunos.

    + +

    Haskell

    + + + +

    Prolog

    + + + +

    Smalltalk

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/design-temario.html b/wiki/articles/design-temario.html new file mode 100644 index 0000000000..4548a6ac89 --- /dev/null +++ b/wiki/articles/design-temario.html @@ -0,0 +1,481 @@ + + + + + + + + + + + Design temario + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Design temario +

    +
    + + + +
    +

    Unidad 1: Diseño y Sistemas

    + + + +

    Unidad 2: Diseño y metodologías

    + + + +

    Unidad 3: Herramientas de concepción y comunicación del diseño

    + + + +

    Unidad 4: Requerimientos y Diseño

    + + + +

    Unidad 5: Modelado de objetos

    + + + +

    Tecnologías

    + +

    Java

    + + + +

    Otras tecnologías

    + + + +

    Una pregunta que muchas veces en la materia diseño es: ¿Que lenguaje uso? Acá van algunas comparativas:

    + + + +

    Unidad 6: Modelado de datos

    + + + +

    Unidad 7: Introducción al diseño de arquitectura

    + + + +

    Unidad 8: Validación del Diseño

    + + + +

    Unidad 9: Diseño de interfaz de usuario

    + +

    Fuera de progama: Diseño funcional y estructurado

    + + + +

    Patrones funcionales en objetos

    + + + +

    Tips de C

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/diagrama-de-clases.html b/wiki/articles/diagrama-de-clases.html new file mode 100644 index 0000000000..0e9501ae31 --- /dev/null +++ b/wiki/articles/diagrama-de-clases.html @@ -0,0 +1,389 @@ + + + + + + + + + + + Diagrama de clases + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Diagrama de clases +

    +
    + + + +
    +

    El diagrama de clases es una herramienta para comunicar el diseño de un programa orientado a objetos, permitiendo modelar las relaciones entre las entidades. En UML, una clase es representada por un rectángulo que posee tres divisiones: Nombre de la clase, atributos que tiene y mensajes que entiende.

    + +

    En el primer cuadro anotamos el nombre de la clase (si es abstracta se escribe en cursiva, o bien se usa un estereotipo <> arriba del nombre de la clase).

    + +

    En la segunda parte (que para nosotros no será de tanta importancia) van los atributos (o variables de instancia, las variables de clase van en subrayado).

    + +

    En el último cuadro escribimos las operaciones (qué mensajes que puede entender). No confundir con los métodos que es cómo lo resuelve cada objeto. Lo importante no es documentar todos los mensajes de un objeto, sino sólo los más relevantes. Así quedan fuera los getters, setters, métodos privados (o auxiliares) y aquellos que uno considere menores. Moraleja: cuidado con las herramientas que en base al código generan el diagrama (y viceversa). Bien vale la pena un diagrama útil hecho a mano antes que uno inútil en 3D.

    + +

    Importante: Una clase que no tiene comportamiento no está comunicando qué rol cumple en la solución: o está faltando definir qué le puedo pedir o esa clase no debería estar en el diagrama.

    + +

    Relaciones entre objetos

    + +

    RELACIÓN “USA”

    + +

    Dependencia: uno de los elementos usa o depende del otro cuando:

    + +
      +
    • El objeto de clase A recibe o devuelve como parámetro de alguno de sus métodos un objeto de clase B
    • +
    + + + +
      +
    • Si el objeto de clase A instancia un objeto de clase B (pero no lo almacena como variable de instancia, sólo vive como variable local en el contexto de un método).
    • +
    + +

    Este tipo de relación indica que los dos elementos colaboran entre sí, pero que esa relación es débil, casual; tiene un contexto temporal que no trasciende más allá de una operación. No obstante, sabemos que los cambios en la clase B podrían impactar en alguna medida en la clase A.

    + +

    + +

    RELACIÓN “CONOCE”

    + +

    Asociación: uno de los elementos conoce al otro, almacenándolo como variable de instancia.

    + +

    Puede definirse una etiqueta que expresa el rol que cumple dicha relación. En cada extremo de la asociación puede agregarse la siguiente información:

    + +
      +
    • un nombre del rol
    • +
    + + + +
      +
    • flechas de navegación: determina el conocimiento (navegabilidad) desde un objeto hacia el otro.
    • +
    + + + +
      +
    • multiplicidad: indica cuántos objetos de una clase se relacionan con la otra. La multiplicidad se puede indicar con un rango (0..1, 2..5), un rango sin cota (0..*, 1..*), un valor (1) o una serie de valores (1, 3, 5).
    • +
    + +

    En las asociaciones, hay una relación más fuerte que en las dependencias (uso) entre ambos elementos. El conocimiento implica que la colaboración excede el marco temporal de una operación, aunque cada uno de los objetos sigue teniendo objetivos diferentes.

    + +

    + +

    Relaciones entre clases

    + +

    RELACION “HEREDA”

    + +

    Generalización: una clase específica hereda los atributos, relaciones, operaciones y métodos de otra más general.

    + +

    Cuando una subclase redefine el comportamiento de su superclase, se escriben los nombres de los métodos que redefine.

    + +

    + +

    RELACIÓN “IMPLEMENTA”

    + +

    Realización: se establece entre una clase y una interfaz; esto implica que la clase debe implementar todas las operaciones que defina la interfaz. Si bien no todos los lenguajes requieren explicitar por código la existencia de una interfaz (en Smalltalk no hace falta, pero en Java sí por tener un checkeo de tipos estático), desde un punto de vista conceptual la interfaz existe y puede comunicarse en el diagrama.

    + +

    + +

    Herramientas para diagramar

    + +

    yUML

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/diccionarios.html b/wiki/articles/diccionarios.html new file mode 100644 index 0000000000..d8031e5e8e --- /dev/null +++ b/wiki/articles/diccionarios.html @@ -0,0 +1,395 @@ + + + + + + + + + + + Diccionarios + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Diccionarios +

    +
    + + + +
    +

    Un Dictionary es un conjunto de asociaciones entre claves y valores, donde tanto las claves como los valores son objetos cualesquiera.

    + +

    Dicho de otra forma: a un Dictionary puedo pedirle que asocie un objeto valor a un objeto clave. Cada clave puede tener asociado un único objeto valor en un Dictionary; si asocio un valor a una clave que ya tenía otro valor asociado, reemplaza el valor viejo por el nuevo.

    + +

    Para esto se le envía al Dictionary el mensaje at:put: que me diga qué objeto tiene asociado a una clave. Si no tiene ninguno, da error… a menos que se lo pida de una forma que evita el error.

    + +

    La forma standard de pedir el valor asociado a una clave es enviarle al Dictionary el mensaje at:; si quiero especificar qué quiero que haga si no encuentra la clave, uso at:ifAbsent: .

    + +

    Un Dictionary es una Collection, entonces los mensajes comunes a todas las Collections se los voy a poder enviar a un Dictionary. Para estos mensajes, se toman sólo los valores, p.ej. si pregunto includes: estoy preguntando si contiene un valor, y en select: / collect: / etc. el parámetro va a ser un valor. A pesar de esto, el resultado del select: será un Dictionary, para los valores para los que el bloque dé true va a incluir el par clave/valor correspondiente.

    + +

    Un ejemplo de todo esto: un sencillo diccionario de traducción de palabras. De esta forma creo un Dictionary y le pongo algunas asociaciones

    + +

    dct := Dictionary new.  +dct at: 'uno' put: 'one'. "Clave 'uno', valor 'one'"  +dct at: 'dos' put: 'two'. "Clave 'dos', valor 'two'"  +dct at: 'tres' put: 'three'.  +dct at: 'cuatro' put: 'four'. 

    + +

    Le pido a dct un elemento

    + +

    dct at: 'tres' "devuelve 'three'"  +dct at: 'cinco' "tira error"  +dct at: 'cinco' ifAbsent: ['no se'] "devuelve 'no se'"  +dct at: 'tres' ifAbsent: ['no se'] "devuelve 'three'" 

    + +

    Le pido cosas de Collection

    + +

    dct size. "devuelve 4"  +dct includes: 'dos' "false, trabaja sobre los valores"  +dct includes: 'two' "true"  +dct select: [:pal | pal size = 4]  "a Dictionary('cuatro' -> 'four'), Analiza sobre los  valores pero devuelve un nuevo diccionario respetando las claves" 

    + +

    Ahora, ¿qué pasa si queremos usar las claves, o necesitamos trabajar con los pares clave/valor? Vamos de a poco.

    + +

    Si a un Dictionary le envío el mensaje keys me devuelve un Set con las claves, en caso:

    + +

    dct keys "devuelve a Set('uno' 'dos' 'cuatro' 'tres')" 

    + +

    Este es un nuevo objeto Set, al que le puedo hacer/preguntar lo que quiera, obviamente que si lo modifico el diccionario no se ve afectado. P.ej.

    + +

    dct keys select: [:pal | pal size = 4]  "devuelve a Set('tres')" 

    + +

    Ahora veamos cómo trabajar con claves y valores a la vez.

    + +

    Primero me pregunto, si quiero trabajar con los pares clave/valor, es probable que tenga que representar cada par como un objeto. ¿Qué objetos van a ser estos?

    + +

    Respuesta: van a ser instancias de la clase Association. Una Association es un par clave/valor, entiende los mensajes key y value.

    + +

    Si a un Dictionary le envío el mensaje associations, va a devolver una OrderedCollection con sus pares clave/valor representados mediante Associations, p.ej.

    + +

    dct associations "devuelve anOrderedCollection('uno' -> 'one'  'dos' -> 'two'  'cuatro' -> 'four'  'tres' -> 'three')"

    + +

    Entonces, si obtengo uno de estos pares, p.ej.

    + +

    dct associations first 

    + +

    obtengo un objeto al que le puedo pedir key y value. P.ej.

    + +

    dct associations first key "respuesta posible: 'uno'"  +dct associations first value "respuesta posible: 'one'" 

    + +

    Otra vez, esta es una colección a la que puedo hacerle cualquier cosa, p.ej.

    + +

    dct associations select: [:assoc | assoc key size = assoc value size] "devuelve an OrderedCollection('uno' -> 'one' 'dos' -> 'two')"

    + +

    Terminamos con otro ejemplo, una implementación de un depósito que se acuerda del stock de cada artículo usando un diccionario donde la clave es el artículo y el valor es la cantidad de unidades del artículo en el depósito.

    + +

    #Depósito (v.i. artículos) + >> initialize +     artículos := Dictionary new. +  + >> cuantoTenésDe: unArtículo  +     ^artículos at: unArtículo  +  + >> pone: cant de: unArtículo  +     artículos at: unArtículo put: (artículos at: unArtículo) + cant  +  + >> saca: cant de: unArtículo  +     artículos at: unArtículo put: (artículos at: unArtículo) - cant  +  + >> cantidadTotalDeUnidades  +     "trabaja sobre los valores, que son las cantidades"  +     ^artículos inject: 0 into: [:x :elem | x + elem].  +  + >> valorTotalDeposito  +    "a assoc key (el artículo) le pido el precio, assoc value es la cantidad de ese artículo en el depósito"  +     ^artículos associations  inject: 0  into: [:x :assoc |  x + assoc key precio * assoc value].

    + +

    Algo importante a tener en cuenta al usar un diccionario es detenerse a pensar si no nos está faltando una abstracción que deberíamos modelar en vez de manejar asociaciones de valores. A una asociación no le podemos agregar comportamiento, con lo cual la lógica que trabaja con los valores asociados está en el objeto que tiene el mapa (como en este caso se puede ver en el producto entre el precio y la cantidad en el depósito), esa asociación bien podría reemplazarse por un objeto propio que conozca al producto y la cantidad que hay en stock al cual sí podríamos agregarle comportamiento. Forma parte de diseñar la solución decidir si es buena idea o no usar un diccionario en vez de una colección con objetos de dominio que, además de asociar otros objetos, tengan responsabilidades propias.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/diferencia-entre-objetos-y-procedural---con-un-ejercicio-de-la-guia-1.html b/wiki/articles/diferencia-entre-objetos-y-procedural---con-un-ejercicio-de-la-guia-1.html new file mode 100644 index 0000000000..f62d98f5fc --- /dev/null +++ b/wiki/articles/diferencia-entre-objetos-y-procedural---con-un-ejercicio-de-la-guia-1.html @@ -0,0 +1,337 @@ + + + + + + + + + + + Diferencia entre objetos y procedural con un ejercicio de la guia 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Diferencia entre objetos y procedural con un ejercicio de la guia 1 +

    +
    + + + +
    +

    Veamos el ejercicio de la guía 1 que habla del sueldo de Pepe. El sueldo de Pepe es su sueldo básico más su bono por presentismo más otras cosas. De bono hay dos tipos

    + +
      +
    • uno que es: 100 pesos si no faltó nunca, 50 pesos si faltó un día, 0 si faltó dos o más días.
    • +
    • otro que es siempre 0
    • +
    + +

    Podrían imaginarse más bonos: uno que es 200 si faltaste hasta 2 veces y 0 si faltaste 3 o más, otro que es lo mismo pero el doble en diciembre, uno que va subiendo 10 pesos cada vez que se paga en meses consecutivos (100 el primer mes, 110 el segundo, etc., así te tentás a no faltar nunca). El ejercicio plantea dos variantes de bono x presentismo para que no se haga tan largo resolverlo, está bueno pensar que puede haber más.

    + +

    Si Pepe puede tener varias variantes de bono por presentismo, no es nada lindo que el código sea algo así

    + +

    calculaPresentismo: diasQueFalto

    + +

       (bonoPorPresentismo = 1)   "el que depende de cuántos días faltó" +   ifTrue: [ +         ( diasQueFalto = 0 ) +              ifTrue:  [^100]. +         ( diasQueFalto = 1 ) +              ifTrue:  [^50]. +         ^0 +   ]. +   (bonoPorPresentismo = 2)  "siempre 0" +   ifTrue: [ +         ^0 +   ]. +   (bonoPorPresentismo = 3)  "otro que aparezca después" +   ifTrue: [ +         ... lo que corresponda en este caso +   ].

    + +

    la salida en este caso es darse cuenta que conviene modelar el bono por presentismo como un objeto distinto de pepe, y que pepe tenga una variable a su bono por presentismo. Se lo seteás desde el workspace. Entonces el que calcula el valor es el bono, para lo cual necesita saber los días que faltó, entonces pepe le pregunta a su bono así:

    + +

       bonoPresentismo importeSegun: diasFaltados

    + +

    donde bonoPresentismo y diasFaltados son variables de pepe.

    + +

    Fíjense que los bonos son todos polimórficos para Pepe.

    + +

    Posta es altísimamente importante que vean esto, es la papota básica de objetos: poder representar cada ente que tiene comportamiento propio (en este caso el bono x presentismo) como un objeto, y si tiene varias variantes que se comportan distinto, hacer varios objetos que sean polimórficos entre sí para los otros objetos que tengan que usar ese comportamiento. Si se entiende bien, muchas cosas (en PDP, en Diseño y después en el laburo) se simplifican.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/diferencias-entre-polimorfismo--abstraccion-y-encapsulamiento.html b/wiki/articles/diferencias-entre-polimorfismo--abstraccion-y-encapsulamiento.html new file mode 100644 index 0000000000..3dc107e378 --- /dev/null +++ b/wiki/articles/diferencias-entre-polimorfismo--abstraccion-y-encapsulamiento.html @@ -0,0 +1,362 @@ + + + + + + + + + + + Diferencias entre polimorfismo abstraccion y encapsulamiento + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Diferencias entre polimorfismo abstraccion y encapsulamiento +

    +
    + + + +
    +

    La discusión se dispara por una consulta sobre el ejercicio 2a de este final de 2009.

    + +

    Un alumno propone los siguientes cambios, los cuales son válidos para lo que se plantea en el ejercicio:

    + +
    +

    Que la variable de instancia tipo referencie a un objeto que puede ser de las clases MateriaPrima, ProductoSemiElaborado y ProductoTerminado, y estas clases sean clases independientes, es decir que no sean subclases de ninguna ya que según el diagrama no comparten características. Entonces ahora Material deja de ser clase abstracta, para crear un material creamos un objeto de la clase Material, y a la variable tipo le asignamos un objeto de la clase de material que corresponda (MateriaPrima, ProductoSemiElaborado o ProductoTerminado).

    +
    + +

    De la mano de esta justificación conceptual:

    + +
    +

    Aprovechariamos el concepto de polimorfismo y el de abstracción, ya que para la clase sector es transparente este cambio (abstracción), ella le va pedir el costoAlmacenamiento() a su lista de materiales y despues cada material le va a pedir a su tipo el costoAlmacenamiento(), aca se aplica el polimorfismo ya que no importa el tipo del material que sea el objeto material, todos los tipos van a entender el mensaje costoAlmacenamiento(). Y aparte esta solución permite que el dia de mañana si se quiere agregar un nuevo tipo de material solo hay que crear la clase de ese nuevo tipo y que en sus metodos de instancia este el método costoAlmacenamiento() y listo, ya se la puede referenciar con la variable de instancia tipo. Esto es una caracteristica tmb no? pero no me acuerdo como se llama.

    +
    + +

    A continuación mostramos la explicación por parte del docente:

    + +
    +

    El único detalle que yo marcaría es con respecto a los conceptos que vos mencionás. Yo creo por la forma en que usás la palabra “abstracción”, lo que estás queriendo decir es “encapsulamiento”.

    + +

    Tal vez es sutil la diferencia, porque se puede ver al encapsulamiento como una forma de abstracción; pero quedaría mejor tu respuesta si hacés el cambio que yo te digo.

    + +

    O sea cuando vos decís “para la clase sector es transparente este cambio”, eso es

    + +
      +
    • encapsulamiento (que los clientes de un objeto no tengan que saber de su implementación interna)
    • +
    • o desacoplamiento (que el cambio a una parte de un sistema no afecte a las otras)
    • +
    + +

    La clave está en la palabra transparente; La abstracción iría por el lado de encontrar una idea o un concepto que capture “la esencia” de (una parte de) mi problema y a partir de ahí me permita guiar el diseño.

    + +

    La abstracción en este caso podría ser el “tipo de material”, las tres clases que vos hacés polimórficas (MateriaPrima, ProductoSemielaborado, ProductoTerminado) en tu solución intentan ser tres versiones de un mismo concepto que no estaba en la solución inicial. Encontrar ese concepto es abstraer o encontrar una abstracción. Pasaste de ideas concretas (MateriaPrima, etc) a una idea más “abstracta” (tipo de material) que permite pensar a los otros como variantes de una misma cosa.

    + +

    El encontrar esa abstracción es lo que te permite luego pensar en hacer a los participantes de esa abstracción polimórficos entre sí.

    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/diseno-iterativo.html b/wiki/articles/diseno-iterativo.html new file mode 100644 index 0000000000..752f7912d2 --- /dev/null +++ b/wiki/articles/diseno-iterativo.html @@ -0,0 +1,377 @@ + + + + + + + + + + + Diseno iterativo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Diseno iterativo +

    +
    + + + +
    +

    La metodología de desarrollo nos lleva a diseñar de dos formas completamente diferentes:

    + +

    Las metodologías predictivas proponen el diseño anticipado, donde se asume que

    + +
      +
    • el análisis ya ha relevado todos los procesos que el usuario necesita
    • +
    • tenemos disponible toda la información para poder definir cada proceso
    • +
    • no habrá cambios en los requerimientos hasta nuestra implementación +
        +
      • el usuario no hará cambios o nuevos pedidos.
      • +
      • no habrá cambios externos al sistema que obliguen a modificarlo (como disposiciones legales).
      • +
      +
    • +
    • si el diseño es adecuado, la codificación se ajustará perfectamente a lo que el usuario necesita. +
        +
      • para ello hay que documentar el sistema en su completitud para que los programadores no tengan que tomar decisiones de diseño en la codificación.
      • +
      +
    • +
    • en la fase de diseño no se debe programar, dado que se estaría solapando la actividad (de la misma manera que en la fase de codificación no se debe diseñar)
    • +
    + +

    Esta forma de diseñar también se conoce como “Big Design Up Front”. En este artículo el autor expone algunos argumentos en favor de esta metodología.

    + +

    Por el contrario, las metodologías adaptativas proponen el diseño iterativo, donde se asume que

    + +
      +
    • sólo tenemos algunos procesos relevados, y aunque los tuviéramos en su totalidad, los requerimientos podrían cambiar.
    • +
    • es inocente pensar en que no habrá cambios en los requerimientos, dado que +
        +
      • el usuario no sabe exactamente lo que se va a construir y tiene derecho a pedir modificaciones cuando se da cuenta de que cometió un error al dar información al diseñador.
      • +
      • bajo la premisa anterior el diseñador no puede realizar un diseño que no esté sujeto a cambios, por los errores propios que además podría cometer.
      • +
      +
    • +
    • si el diseño no es adecuado, debemos cambiarlo lo más pronto posible. Esto incluye la fase de codificación.
    • +
    • si queremos reflejar la realidad, tenemos que permitir que haya alternancia entre diseño y programación. No paralelizamos las actividades, sino que una se va solapando a la otra, como en una pila.
    • +
    • el diseño iterativo considera que los errores son parte del desarrollo mismo y necesitamos poder modificar el diseño en cualquier momento, sin que eso paralice el proyecto (iterativo tiene mucho de “prueba y error”).
    • +
    • simplest thing that could possible work
    • +
    • En este artículo Martin Fowler explica el diseño desde el punto de vista de las metodologías ágiles.
    • +
    + +

    El costo del cambio

    + +

    Tradicionalmente las metodologías secuenciales interpretan que le costo de corregir un error o de introducir un cambio en un desarrollo de software se incrementa exponencialmente a medida que se avanza con el desarrollo. Según esta visión, un error en el análisis que podría corregirse en un par de horas de trabajo, tardará días en solucionarse si se lo detecta durante la etapa de diseño e incluso podría requerir de varias semanas si se lo encuentra recién durante la etapa de construcción.

    + +

    Varios autores, entre ellos Kent Beck han propuesto otra interpretación. Según esta nueva perspectiva la curva del cambio es radicalmente distinta para los proyectos de software en la actualidad. La valoración incorrecta del costo del cambio proviene en parte por la asociación con otras ingenierías; en las ingenierías que trabajan con entidades físicas hacer una modificación sobre algo construido suele ser muy costoso, incluso en algunos casos imposible. Esto no es válido para una ingeniería que trabaja con productos tan abstractos y maleables como el software. Adicionalmente la ingeniería del software se diferencia radicalmente de las otras en cuanto a que el costo de reproducción de un producto una vez construido es insignificante (compárese el costo de construir una nueva unidad de un automóvil determinado en una línea de producción con el costo de producir una nueva unidad de un programa que se vende en forma masiva).

    + +

    Por otro lado, las herramientas para el desarrollo de software han evolucionado notablemente en los últimos años, apareciendo entornos integrados de desarrollo, lenguajes de muy alto nivel, herramientas de versionado, refactorings automáticos, herramientas de integración contínua, entre otros. A modo de ejemplo, podemos considerar el costo de cambiar el nombre de una variable en un entorno de desarrollo que no tenga la capacidad de hacerlo automáticamente en un programa grande con la simplicidad de hacerlo en un entorno de los que se usan hoy en día. El tiempo se reduce apenas a segundos.

    + +

    Según la interpretación de Beck, cualquier cambio es realizable con un costo relativamente bajo aun en etapas avanzadas del desarrollo. Otros autores sugieren que hay algunos cambios para los cuales se puede aplanar la curva del costo y otros cambios para los que no. Por ejemplo, se ha sugerido que los errores arquitecturales tienden a tener curvas empinadas. Si bien es imaginable que en la medida que las herramientas (tanto tecnológicas como conceptuales) evolucionen, más y más decisiones puedan tomarse considerando la posibilidad de modidicarlas mas adelante sin que esto implique un costo alto, todavía hoy en día es importante detectar para cada decisión que tomamos en una etapa temprana del desarrollo si el costo potencial de un error es elevado o no.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/diseno-y-sistemas-de-tipos.html b/wiki/articles/diseno-y-sistemas-de-tipos.html new file mode 100644 index 0000000000..7e6729a865 --- /dev/null +++ b/wiki/articles/diseno-y-sistemas-de-tipos.html @@ -0,0 +1,355 @@ + + + + + + + + + + + Diseno y sistemas de tipos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Diseno y sistemas de tipos +

    +
    + + + +
    +

    En programación el chequeo estático de tipos permite detectar errores en un programa de forma previa a su ejecución. Existen amantes y detractores de esta idea y existen lenguajes profesionales con y sin chequeo de tipos. Quienes apoyan el uso de estos mecanismos sostienen que este tipo de chequeos garantiza o ayuda a garantizar la ausencia de errores en los programas, mientras que los que prefieren evitar estos chequeos sostienen que:

    + +
      +
    • a menudo resultan limitantes descartando soluciones que podrían ser viables
    • +
    • que agregar la información de tipos a un programa es trabajoso y reduce su legibilidad y finalmente
    • +
    • que las garantías que otorga un sistema de tipos pueden lograrse por otros mecanismos (como el testeo unitario).
    • +
    + +

    ¿Cómo afecta el chequeo de tipos a la actividad de diseño?

    + +
      +
    • Si para diseñar utilizamos herramientas capaces de validarlos, entonces podrían ayudar a detectar errores. De estas herramientas podemos ver dos sabores: +
        +
      • Herramientas que permiten construir diagramas y realizan chequeos sobre esos diagramas.
      • +
      • Si utilizamos código, o pseudo-código como herramientas dentro del proceso de diseño, podemos utilizar los chequeos de tipos en esos programas para detectar problemas. Esto puede resultar particularmente importante al realizar rediseños y pruebas de rediseño sobre un programa ya construido.
      • +
      +
    • +
    • El sistema de tipos de la tecnología en la que se construye el programa diseñado establece restricciones sobre lo que se puede programar en ese lenguaje; entonces, si al diseñar no tengo en cuenta esas restricciones corro el riesgo de producir un diseño que luego no es fácil (o incluso no es posible) de construir en la tecnología elegida. El sistema de tipos forma parte del metamodelo del lenguaje de programación; uno puede elegir establecer una relación más o menos cercana entre ambos metamodelos, con las consecuencias ya explicadas.
    • +
    • Finalmente, un tipo determina el conjunto de operaciones que se puede realizar sobre una entidad (entre otras cosas). Por entidad podemos entender cualquier porción de un sistema: objeto, clase, procedimiento, subsistema, tipo abstracto de datos, etc. Es posible establecer una relación directa entre las operaciones y las responsabilidades e interfaces asociadas a una parte de un sistema (que son objetivos específicos del diseño). Definir tipos es una forma de definir las interfaces entre entidades de software.
    • +
    • Adicionalmente en sistemas de tipos con presencia de polimorfismo, un tipo no define la interfaz de una entidad sino que define un contrato que podrían cumplir múltiples entidades distintas.
    • +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/diseno-y-tecnologia.html b/wiki/articles/diseno-y-tecnologia.html new file mode 100644 index 0000000000..5586d00ba5 --- /dev/null +++ b/wiki/articles/diseno-y-tecnologia.html @@ -0,0 +1,360 @@ + + + + + + + + + + + Diseno y tecnologia + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Diseno y tecnologia +

    +
    + + + +
    +

    Existe una fuerte relación entre diseño y la programación, o mejor dicho, entre el diseño y la tecnología que voy a utilizar para construir el sistema.

    + +

    El nivel de detalle del diseño

    + +

    En primer lugar podemos analizar el nivel de detalle de ambos. Obviamente el programa tendrá muchos detalles más que el diseño, necesita poder ser compilado y ejecutado, incluir todos esos detalles en la especificación de diseño sería contraproducente porque nos obligamos a decidir sobre cada uno de esos puntos y tal vez convenga postergar algunas decisiones para el momento de programar. En el extremo, si el diseño definiera todos los detalles del programa subyacente, entonces la programación posterior no requiere de tomar ninguna decisión y por lo tanto podría automatizarse. En ese caso la programación deja de tener sentido como actividad, la puedo considerar un paso más de la compilación y nuestro diseño podría considerarse directamente como un programa.

    + +

    A medida que los lenguajes de programación fueron siendo cada vez de más alto nivel y fueron incorporando mejores abstracciones (podemos destacar el manejo automático de memoria como un ejemplo esencial), la diferencia entre el nivel de abstracción del diseño y del programa se fue achicando. En la literatura podemos encontrar dos visiones de este proceso. Algunas metodologías como MDA consideran que sólo debemos diseñar y debemos descartar la programación como actividad. Entonces la ingeniería de software debería dedicarse a producir modelos, y los programas deberían derivarse automáticamente de esos modelos. Otras metodologías como XP incorporan el diseño como parte de la actividad, y entonces consideran que la única actividad es la programación. Como referencia de este pensamiento puede leerse el artículo de Martin Fowler: Is Design Dead?

    + +

    Ambas visiones no son tan distintas entre sí, en definitiva el diseño y el programa se acercan, y finalmente la única discusión restante es si nuestros modelos/programas deberán tener forma de diagrama o si tendrán forma de texto. (¿Y si se combinan ambos? ¿Hay otras posibilidades?… todas son preguntas para las que hoy la ciencia del desarrollo de software no tiene respuestas únicas)

    + +

    Por otro lado, un diseño de muy alto nivel deja muchos detalles a responsabilidad de la persona que va a construir. Si el modelo deja abiertas cuestiones que tienen que ver (por ejemplo) con la forma en que se estructurará el programa entonces está postergando decisiones que son de diseño aunque las tome una persona cuyo rol formal es el de programador. En ese caso lo que pasa es que el programador es el que está llevando a cabo el nivel más detallado del diseño. Esto no tiene por qué ser algo negativo, es una forma de organización perfectamente válida, en la cual algunas personas toman la responsabilidad del diseño a alto nivel (podría llamarse incluso arquitectura) y a otras les toca ocuparse del diseño más detallado.

    + +

    Metamodelos en el diseño y metamodelos en el programa

    + +

    La otra perspectiva desde la que podríamos analizar la relación entre diseño y tecnología es pensar la relación entre el metamodelo que usamos para diseñar y el metamodelo del lenguaje que usaremos para construir.

    + +

    Si esos metamodelos coinciden entonces lo que yo diseñe puede que sea más fácil de construir (o de visualizar la relación entre lo construido y el modelo). Pero, de nuevo, un metamodelo para un programa puede requerir de muchos detalles que en determinado momento del diseño todavía no estoy en condiciones de decidir. Un ejemplo común es tener que decidir si queremos poner una clase abstracta o una interfaz cuando todavía no hemos definido los detalles del concepto asociado.

    + +

    Entonces dependiendo del nivel de detalle de nuestro diseño tal vez convenga elegir metamodelos más o menos parecidos a los metamodelos de nuestra tecnología subyacente:

    + +
      +
    • Utilizar metamodelos sutilmente diferentes nos permite diseñar con más libertad, desprendiéndonos de complejidades y restricciones tecnológicas.
    • +
    • Pero las diferencias entre ambos metamodelos plantean “gaps” que luego habrá que resolver al construir, entonces no podemos permitir que ambos metamodelos tengan diferencias demasiado fundamentales.
    • +
    + +

    En resumen, el diseño es la especificación de lo que quiero construir. Entonces, al elegir la forma en la que quiero diseñar, las herramientas que uso para diseñar tengo que entender la relación que establezco con la tecnología usada para la construcción.

    + +
      +
    • Si las dos ideas se parecen mucho eso puede plantear restricciones muy tempranamente, si planteo actividades distintas es porque quiero ponerles focos distintos, usar herramientas distintas.
    • +
    • Pero si las dos ideas van por caminos muy distintos entonces puede que el diseño pierda utilidad, porque para poder construir voy a tener que llenar los huecos (gaps) que el modelo de diseño no cubra. En definitiva, no es posible construir sin llenar esos huecos, y llenar esos huecos es diseñar.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/distinct.html b/wiki/articles/distinct.html new file mode 100644 index 0000000000..797124c721 --- /dev/null +++ b/wiki/articles/distinct.html @@ -0,0 +1,331 @@ + + + + + + + + + + + Paradigma logico, Predicado distinct + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico, Predicado distinct +

    +
    + + + +
    +

    Motivación

    + +

    ¿Qué pasa cuando un predicado encuentra la misma respuesta por varios caminos?

    + +

    Si tenés:

    +
    ?- esPicaro(Quien).
    +Quien=pepe,
    +Quien=pepe,
    +Quien=juan,
    +Quien=pepe,
    +Quien=juan.
    +
    + +

    ¡Esto está bien! No importa por cuántos caminos llegue a la misma persona, lo que importa es que cuando unifique unifique con los que son pícaros.

    + +

    El problema es cuando querés encontrar cuántos pícaros son, es decir, cuando querés agregar los datos. Por ejemplo harías:

    + +
    findall(Picaro,esPicaro(Picaro),Picaros),
    +length(Picaros,CuantosPicaros).
    +
    + +

    Y querés que te dé 2 (pepe y juan), no 5.

    + +

    Bueno, en ese caso, podés utilizar el predicado de orden superior distinct/2, de esta forma:

    +
    ?- distinct(Quien,esPicaro(Quien)).
    +Quien=pepe,
    +Quien=juan.
    +
    + +

    Y entonces te queda así:

    +
    findall(Picaro,distinct(Picaro,esPicaro(Picaro)),Picaros),
    +length(Picaros,CuantosPicaros).
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/dont-cross-the-beams.html b/wiki/articles/dont-cross-the-beams.html new file mode 100644 index 0000000000..76fabb5317 --- /dev/null +++ b/wiki/articles/dont-cross-the-beams.html @@ -0,0 +1,446 @@ + + + + + + + + + + + Dont Cross the Beams by Kent Beck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Dont Cross the Beams by Kent Beck +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Origen

    + +

    Actualmente threeriversinstituteorg no esta activo, tome el articulo de Kent Beck de archives.org en este [link](http://web.archive.org/web/20130113095840/http://www.threeriversinstitute.org/blog/?p=594)

    + +

    Articulo

    + +

    Intro

    + +

    As many of my pair programming partners could tell you, I have the annoying habit of saying “Stop thinking” during refactoring. I’ve always known this isn’t exactly what I meant, because I can’t mean it literally, but I’ve never had a better explanation of what I meant until now. So, apologies y’all, here’s what I wished I had said.

    + +

    One of the challenges of refactoring is succession–how to slice the work of a refactoring into safe steps and how to order those steps. The two factors complicating succession in refactoring are efficiency and uncertainty. Working in safe steps it’s imperative to take those steps as quickly as possible to achieve overall efficiency. At the same time, refactorings are frequently uncertain–”I think I can move this field over there, but I’m not sure”–and going down a dead-end at high speed is not actually efficient.

    + +

    Inexperienced responsive designers can get in a state where they try to move quickly on refactorings that are unlikely to work out, get burned, then move slowly and cautiously on refactorings that are sure to pay off. Sometimes they will make real progress, but go try a risky refactoring before reaching a stable-but-incomplete state. Thinking of refactorings as horizontal and vertical is a heuristic for turning this situation around–eliminating risk quickly and exploiting proven opportunities efficiently.

    + +

    The other day I was in the middle of a big refactoring when I recognized the difference between horizontal and vertical refactorings and realized that the code we were working on would make a good example (good examples are by far the hardest part of explaining design). The code in question selected a subset of menu items for inclusion in a user interface. The original code was ten if statements in a row. Some of the conditions were similar, but none were identical. Our first step was to extract 10 Choice objects, each of which had an isValid method and a widget method.

    + +

    before:

    + +
    +
    +
    +      if (...choice 1 valid...) {
    +  add($widget1);
    +}
    +if (...choice 2 valid...) {
    +  add($widget2);
    +}
    +... 
    +
    +    
    +
    +
    + +

    after:

    + +
    +
    +
    +      $choices = array(new Choice1(), new Choice2(), ...);
    +foreach ($choices as $each)
    +  if ($each->isValid())
    +    add($each->widget());
    +
    +    
    +
    +
    + +

    After we had done this, we noticed that the isValid methods had feature envy. Each of them extracted data from an A and a B and used that data to determine whether the choice would be added.

    + +

    + +

    + +
    +
    +
    +      Choice1 isValid() {
    +  $data1 = $this->a->data1;
    +  $data2 = $this->a->data2;
    +  $data3 = $this->a->b->data3;
    +  $data4 = $this->a->b->data4;
    +  return ...some expression of data1-4...;
    +}
    +
    +    
    +
    +
    + +

    We wanted to move the logic to the data.

    + +

    + +

    + +
    +
    +
    +      Choice1 isValid() {
    +  return $this->a->isChoice1Valid();
    +}
    +A isChoice1Valid() {
    +  return ...some expression of data1-2 && $this-b->isChoice1Valid();
    +}
    +
    +    
    +
    +
    + +

    Succession

    + +

    Which Choice should we work on first? Should we move logic to A first and then B, or B first and then A? How much do we work on one Choice before moving to the next? What about other refactoring opportunities we see as we go along? These are the kinds of succession questions that make refactoring an art.

    + +

    Since we only suspected that it would be possible to move the isValid methods to A, it didn’t matter much which Choice we started with. The first question to answer was, “Can we move logic to A?” We picked Choice. The refactoring worked, so we had code that looked like:

    + +

    + +

    + +
    +
    +
    +      A isChoice1Valid() {
    +  $data3 = $this->b->data3;
    +  $data4 = $this->b->data4;
    +  return ...some expression of data1-4...;
    +}
    +
    +    
    +
    +
    + +

    Again we had a succession decision. Do we move part of the logic along to B or do we go on to the next Choice? I pushed for a change of direction, to go on to the next Choice. I had a couple of reasons:

    + +
      +
    • The code was already clearly cleaner and I wanted to realize that value if possible by refactoring all of the Choices.
    • +
    • One of the other Choices might still be a problem, and the further we went with our current line of refactoring, the more time we would waste if we hit a dead end and had to backtrack.
    • +
    + +

    The first refactoring (move a method to A) is a vertical refactoring. I think of it as moving a method or field up or down the call stack, hence the “vertical” tag. The phase of refactoring where we repeat our success with a bunch of siblings is horizontal, by contrast, because there is no clear ordering between, in our case, the different Choices.

    + +

    Because we knew that moving the method into A could work, while we were refactoring the other Choices we paid attention to optimization. We tried to come up with creative ways to accomplish the same refactoring safely, but with fewer steps by composing various smaller refactorings in different ways. By putting our heads down and getting through the other nine Choices, we got them done quickly and validated that none of them contained hidden complexities that would invalidate our plan.

    + +

    Doing the same thing ten times in a row is boring. Half way through my partner started getting good ideas about how to move some of the functionality to B. That’s when I told him to stop thinking. I don’t actually want him to stop thinking, I just wanted him to stay focused on what we were doing. There’s no sense pounding a piton in half way then stopping because you see where you want to pound the next one in.

    + +

    As it turned out, by the time we were done moving logic to A, we were tired enough that resting was our most productive activity. However, we had code in a consistent state (all the implementations of isValid simply delegated to A) and we knew exactly what we wanted to do next.

    + +

    Conclusion

    + +

    Not all refactorings require horizontal phases. If you have one big ugly method, you create a Method Object for it, and break the method into tidy shiny pieces, you may be working vertically the whole time. However, when you have multiple callers to refactor or multiple implementors to refactor, it’s time to begin paying attention to going back and forth between vertical and horizontal, keeping the two separate, and staying aware of how deep to push the vertical refactorings.

    + +

    Keeping an index card next to my computer helps me stay focused. When I see the opportunity for a vertical refactoring in the midst of a horizontal phase (or vice versa) I jot the idea down on the card and get back to what I was doing. This allows me to efficiently finish one job before moving onto the next, while at the same time not losing any good ideas. At its best, this process feels like meditation, where you stay aware of your breath and don’t get caught in the spiral of your own thoughts.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/double-dispatch.html b/wiki/articles/double-dispatch.html new file mode 100644 index 0000000000..e7b91f93a7 --- /dev/null +++ b/wiki/articles/double-dispatch.html @@ -0,0 +1,373 @@ + + + + + + + + + + + Double dispatch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Double dispatch +

    +
    + + + +
    +

    Double dispatch es un patrón de diseño que permite de tomar una decision a partir de varios objetos en vez de uno solo. +En las implementaciones de lenguajes de objetos mainstream, la decisión de qué método se va a ejecutar se hace a partir del objeto receptor del mensaje. +Sin embargo, a veces con el objeto receptor no alcanza.

    + +

    Para dar un ejemplo trivial pero ilustrativo, en el juego de piedra, papel, tijera, la decision de quien gana y quien pierde depende de dos objetos y no de uno solo. +En dicho caso, una solución posible es que uno de los dos objetos delegue la decisión al segundo, dándole información de sí mismo. En este caso, el primer objeto va a avisarle al segundo objeto quién es (en este caso una piedra), y el segundo objeto va a decidir quien gana sabiendo eso: otra piedra va a decidir empate, una tijera que gana la piedra, y un papel que gana el papel.

    + +
    Piedra >> quienGanaContra: otro
    +  ^ otro quienGanaContraPiedra: self
    +
    +Piedra >> quienGanaContraPiedra: unaPiedra
    +  ^ nil
    +  
    +Papel >> quienGanaContraPiedra: unaPiedra
    +  ^ self
    +  
    +Tijera >> quienGanaContraPiedra: unaPiedra
    +  ^ unaPiedra
    +
    +...
    +
    + +

    Una definición posible de Double Dispatch, es la propuesta por Ralph Johnson.

    + +

    ¿Qué criterio de dispatch utilizar?

    + +

    Johnson entiende que el Double Dispatch siempre va a sociado a la clase del segundo objeto; si bien comprende eso como un Code Smell lo asume inevitable y característico del Double Dispatch.

    + +

    Sin embargo, otra forma de interpretarlo sería que el mejor Double Dispatch es el que logra evitar el code smell y en lugar de realizar el dispatch sobre el tipo del parámetro lo hace en función al rol que ocupa, es decir, dándole significado más allá del tipo en sí. Por supuesto este tipo de double dispatch requiere de un diseño un poco más, pero es esperable que sea más extensible: si el dispatch se realiza por el tipo tenemos dos desventajas claras:

    + +
      +
    • Explosión combinatoria (como explica Johnson si tenemos 6 subtipos diferentes podemos tener 6x6 combinaciones de dispatchs).
    • +
    • No extensible, ya que agregar un nuevo tipo implicaría necesariamente agregar todas las combinaciones posibles.
    • +
    + +

    Esto no descarta la posibilidad de realizar un double dispatch basado en tipos, pero considera que el code smell no puede ser ignorado y por lo se prefiere evitar esa forma de utilización. En una estrategia de dispatch basada en el comportamiento de los objetos, es más probable que los nuevos casos que surjan puedan asociarse a alguno de los roles preexistentes.

    + +

    ¿Qué usos tiene?

    + +

    Unos de los usos principales del double dispatch son los patrones de diseño de objetos visitor e interpreter. +El patrón visitor sirve para hacer extensible una estructura de datos, modelando operaciones sobre la estructura como objetos “visitantes”. +Los usuarios pueden definir nuevos visitantes, y cada visitante sabe como tiene que manipular cada objeto en la estructura de datos usando el double dispatch.

    + +

    Otro posible uso es para implementar el patron interpreter, un patron usado para evaluar sentencias de un programa. +En el patron interpreter, un programa se representa como un árbol, sobre el que uno puede implementar el patron visitor, donde un objeto intérprete juegue el rol de visitante.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/dsl.html b/wiki/articles/dsl.html new file mode 100644 index 0000000000..38d85fd7af --- /dev/null +++ b/wiki/articles/dsl.html @@ -0,0 +1,518 @@ + + + + + + + + + + + Dsl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Dsl +

    +
    + + + +
    +

    DSL viene de las siglas en inglés Domain-Specific Language.

    + +

    Un DSL es un lenguaje ideado para expresar cierta parte de un sistema. Por eso se dice que es un lenguaje de propósito específico, a diferencia de los lenguajes de propósito general (GPL).

    + +

    Los lenguajes con los que estamos acostumbrados a trabajar, como Java, Haskell o Groovy tienen la característica de que pueden ser utilizados para resolver problemas de programación de cualquier índole, por lo que decimos que son lenguajes de propósito general (GPL por sus siglas en inglés).

    + +

    Estos lenguajes son Turing-complete, siendo capaces de expresar cualquier algoritmo, y pudiendo ser aplicados a cualquier dominio. Con estos lenguajes, con mayor o menor facilidad o eficiencia, podemos construir sistemas de cálculo impositivo, implementar algoritmos de aprendizaje de máquina, etc. Es decir, son lenguajes que pretenden ser igualmente efectivos (igualmente buenos o malos) en todos los campos de accion.

    + +

    Sin embargo, el empleo GPLs para expresar problemas muy específicos, si bien es posible, puede significar mayor esfuerzo de lo que uno desearía, dado que las abstracciones que estos dominios plantean no están soportadas nativamente por el lenguaje; no son primitivas. Por ejemplo, escribir una transposición de matrices, aún contando con API bien diseñada, es ciertamente más complejo en Java que en Mathematica u Octave, y lenguajes como SQL están específicamente diseñados para realizar operaciones sobre una base datos.

    + +

    Estos lenguajes son específicos de un dominio particular (DSL, domain-specific languages), y si bien no pueden resolver todos los problemas, resuelven aquellos para los que fueron diseñados mejor que los GPL.

    + +

    Qué quiere decir esto ?

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
     propósito generalpropósito específico
    Abarca construirla totalidad de la aplicaciónuna parte de la aplicación
    Tipo de Aplicacíóncualquieraun solo tipo
    Conceptosgenerales: 
    + +
                      -   función (en funcional),                        
    +                  -   clase, objeto, método (en OOP),                
    +                  -   variable, predicado (en lógico)...             | del (único) dominio                                                                                                                                                                                    | | Ejemplos           | C, Java, Smalltalk, Self, ADA, Haskell, Prolog... | [xpath](http://es.wikipedia.org/wiki/XPath), SQL, [pic](http://macroexpand.org/doku.php?id=articles:uml-sequence-diagram-dsl-txl:start), [sed](http://es.wikipedia.org/wiki/Sed_(inform%C3%A1tica))... |
    +
    + +

    Problema que ataca un DSL

    + +

    En general cuando nos enfrentamos a un problema de programación aparecen varias actividades que trataremos de simplificar ampliamente acá:

    + +
      +
    1. Entendimiento del problema/dominio
    2. +
    3. Formación conceptual de una solución
    4. +
    5. Implementación en un lenguaje de programación
    6. +
    7. Compilación, ejecución y pruebas.
    8. +
    + +

    Normalmente trabajamos con un único paradigma de programación y unos pocos lenguajes. Estos lenguajes permiten expresar sobre ellos cualquier tipo de dominio, es decir que se utilizan para desarrollar cualquier tipo de aplicación. Por esto es que se llaman lenguajes de propósito general (GPL del inglés).

    + +

    En el proceso de entendimiento del dominio podríamos trabajar completamente abstractos del lenguaje de programación, simplemente tratando de relevar información y requerimientos. No vamos a entrar en detalles acá acerca de esta etapa, pero lo que nos interesa es que se podría hacer una análisis del problema independiente del lenguaje de programación y hasta del paradigma.

    + +

    Durante la formación conceptual de una solución ya debemos pensar el dominio dentro de uno o varios paradigmas (en caso en que osemos desarrollar la solución con múltiples paradigmas), de acuerdo a nuestra experiencia, o lo que veamos que mejor se adapte a la problemática.

    + +

    Por ejemplo, hay problemas que son inherentemente más fáciles de implementar en el paradigma lógico que en objetos, o funcional, etc. Sin embargo, todavía podríamos pensar en una solución independiente del lenguaje.

    + +

    Por ejemplo, en objetos es donde identificamos:

    + +
      +
    • objetos y clases.
    • +
    • responsabilidades (mensajes).
    • +
    • interacciones y colaboraciones.
    • +
    • jerarquías / traits (lógica común y reutilización.
    • +
    • etc.
    • +
    + +

    Luego tenemos que realmente implementar esta solución abstracta en los pasos 3 y 4, y para eso utilizamos un GPL.

    + +

    Y acá va el problema:

    + +
      +
    • El mapeo de la solución conceptual con el lenguaje no es directo, no suele ser trivial.
    • +
    • A veces no tenemos soporte del lenguaje para ciertas abstracciones de nuestro dominio: Los ejemplos más simples son los patrones como singleton, delegación automática, etc.
    • +
    • Estamos forzados a adaptar el dominio y nuestra solución al lenguaje.
    • +
    + +

    Y eso es lo que hacemos siempre, adaptamos al lenguaje que tenemos “a mano”. Eso nos lleva a que nuestra solución va a estar siempre de aquí en adelante expresada en un lenguaje que no es el más cercano al problema/dominio, sino más bien a un lenguaje de programación general.

    + +

    Algunas consecuencias:

    + +

    Legibilidad:

    + +
      +
    • Nuestro código contendrá una mezcla entre conceptos de dominio (una Cuenta, un Cliente, etc) y palabras propias del lenguajes (keywords, como public class, trait, etc).
    • +
    • Quien se incorpore al proyecto o quiera revisar la solución deberá, naturalmente, hacer el proceso inverso, como una ingeniería reversa, a partir del código y de lo expresado en el GPL abstraerse para generar una representación mental del problema/dominio.
    • +
    + +

    Flexibilidad (cambios de requerimientos o dominio):

    + +
      +
    • Naturalmente solo podrán ser implementados por desarrolladores que entiendan no solo el dominio, sino además el GPL.
    • +
    • Cada nuevo cambio deberá ser traducido nuevamente de dominio hacia GPL.
    • +
    + +

    Duplicación:

    + +
      +
    • Tendremos al menos dos representaciones de la solución, la mental (que muchas veces además se plasma en documentos de especificación y análisis) y la traducción/implementación en el GPL.
    • +
    + +

    Estas consecuencias hacen que la programación dedique la mayor parte del tiempo y esfuerzo en lidiar con los problemas de traducción e implementación de la solución al GPL.

    + +

    Entonces, una vía alternativa sería en pensar que en lugar de adaptar nuestra solución a un lenguaje, podemos adaptar el lenguaje a nuestra solución.

    + +

    A esto se lo conoce como Language-Oriented Programming, desde el punto de vista de un nuevo “paradigma”. Y una de las prácticas es crear un nuevo lenguaje para expresar nuestra solución o una parte de la solución. Esto es un DSL.

    + +

    Motivación para hacer un DSL

    + +

    Suponemos que con la comparación que ya vimos, aparecen varias razones. Pero vamos a enumerarlas acá para resumir:

    + +
      +
    • para acercar la brecha entre la descripción del problema en términos abstractos (descripción del dominio) y la implementación de la “computación” que lo resuelve / ejecuta. +
        +
      • Facilitaría la comunicación con gente no-técnica.
      • +
      • No programadores podrían entenderlo y escribirlo.
      • +
      +
    • +
    • para esconder los detalles internos +
        +
      • de la lógica común
      • +
      • o las construcciones propias del lenguaje
      • +
      +
    • +
    • para configuraciones de ciertas partes de la aplicación.
    • +
    • para expresar de forma declarativa ciertas reglas del negocio, que se va a separar de la forma en que se interprete y ejecute esa regla. Ej: regular expressions.
    • +
    • para la creación de un grafo complejo de objetos, problema que normalmente solucionamos con patrones creacionales, como factories, builders & prototypes.
    • +
    + +

    ¿Cuando necesito un DSL? Como aproximación, diremos que si la cantidad de problemas en este domino específico que queremos resolver es pequeño, o la complejidad de crear el DSL es mayor que la resolver el problema en nuestro GPL, probablemente no lo necesitemos. De lo contrario, será una alternativa a considerar.

    + +

    Tipos de DSL’s

    + +

    A grandes rasgos, podríamos catalogar los DSLs a través de las siguientes categorías. Existen autores que refinan mucho más a detalle la categorización, incluyendo nuevos tipos. A fines prácticos de explicar la idea general a nivel de programación, nosotros optamos por acotar esa categorización:

    + +
      +
    • Parser + Compilador ó Interprete +
        +
      • Compilador: traduce a lenguaje maquina ejecutable: puede ser assembler o un lenguaje ejecutable por una VM como java, etc.
      • +
      • Interprete: a medida que se va parseando (leyendo) el código de expresado en el DSL, se va ejecutando, sin haber “generado” código ejecutable como paso intermedio.
      • +
      +
    • +
    • Traductor: +
        +
      • son los famosos generadores de código.
      • +
      • si bien se podría trazar una analogía con los compiladores, ya que también generan código, la diferencia es que los traductores generan código que no es “ejecutable” de por sí, sino más bien código de otro lenguaje.
      • +
      • Ejemplo: generadores de código. a través de Java APT (annotation processing tool)
      • +
      +
    • +
    • Embebidos: +
        +
      • se utiliza un lenguaje GPL, pero se lo usa de tal manera de “simular” o asemejarse lo mayor posible a un lenguaje propio del dominio
      • +
      • con syntax sugar y un diseño de API’s especial, llamado Fluent Interfaces, se acerca de un lenguaje de dominio.
      • +
      • aprovechar las características del lenguaje GPL existente,
      • +
      • Evita tener que hacer un parser, compilador e interprete.
      • +
      • Ej: ruby
      • +
      +
    • +
    + +

    DSL Interno

    + +

    Desarrollados como un API dentro de un lenguaje de proposito general, que se ejecutan en su mismo ambiente, llamado lenguaje huésped.

    + +

    Si comparamos los DSLs internos y externos, en general los segundos serán mas flexibles, pero también el esfuerzo de implementarlos será mayor, no sólo porque la complejidad de implementar un parser a mano es mayor, sino que probablemente el lenguaje huésped nos proveerá muchas construcciones y bibliotecas útiles. (Digresión: aprovechar las bibliotecas existentes para otro lenguaje es un punto muy importante también a la hora de diseñar un GPL. Así es como surge gran cantidad de lenguajes que corren sobre la máquina virtual de Java o .Net)

    + +

    Ejemplo de DSL interno para definir especificaciones aprovechando features de lenguajes dinámicos

    + +

    DSL Externo

    + +

    Desarrollados como un lenguaje independiente, compilado, interpretado o una mezcla de ambos, que se ejecuta en un ambiente independiente, y no guarda necesariamente relación con el lenguaje en que está escrito el parser.

    + +

    Ventajas

    + +
      +
    • Libertad absoluta sobre la sintaxis del lenguaje (solo limitada por capacidad de implementación del parser, etc), por eso..
    • +
    • Mayor expresividad del dominio.
    • +
    + +

    Desventajas

    + +
      +
    • Complejidad al tener que implementar el parser + compiler
    • +
    • Disasociación del lenguaje “base” o de ejecución.
    • +
    • Caemos fuera de las herramientas tradicionales, y perdemos soporte a nivel IDE (salvo, ahora con xtext)
    • +
    + +

    Artículo sobre cómo hacer un DSL externo usando XText

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/efectos-y-diseno.html b/wiki/articles/efectos-y-diseno.html new file mode 100644 index 0000000000..98fcbc3db2 --- /dev/null +++ b/wiki/articles/efectos-y-diseno.html @@ -0,0 +1,351 @@ + + + + + + + + + + + Efectos y diseno + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Efectos y diseno +

    +
    + + + +
    +

    Entendemos por efectos (colaterales) a aquellas modificaciones observables sobre el ambiente que son producidas por, y persisten tras, la ejecución de un programa.

    + +

    Son ejemplos de efectos:

    + +
      +
    • la impresión de un mensaje por consola o un cuadro de diálogo en una interfaz gráfica
    • +
    • la asignación destructiva de una variable en un programa procedural
    • +
    • el encendido de una lámpara o la apertura de una compuerta
    • +
    • La eliminación de un registro en una base de datos
    • +
    • El envío de un correo electrónico.
    • +
    + +

    En un sentido amplio, no es posible eliminar completamente los efectos: un sistema (software o no) que no presente efecto no será capaz de transformar su entorno, y por lo tanto, será inútil completamente: por ejemplo de nada sirve generar un informe sobre contaminación del agua si luego este no es tomado en cuenta en los controles.

    + +

    Por el contrario, los sistemas reales modifican de forma observable su mundo, recopilando información y actuando.

    + +

    Al hablar de efectos, es importante remarcar la importancia del observador, el nivel de detalle y alcance al que estamos analizando el problema. Por ejemplo, la impresión en papel de un informe, desde el punto de vista de la cola de impresión es una operación con efecto, pero desde el punto de vista de un gerente, no lo tiene en tanto no llegue a sus manos y se tomen acciones en base a su contenido. Desde el punto de vista del microprocesador, una simple suma tiene efecto en tanto implica modificaciones en sus registros.

    + +

    Aquí solo consideraremos como efectos aquellos que sean observables por o mas allá de nuestro código, dejando fuera todo aquel efecto completamente encapsulado en el motor, como la Máquina Virtual de Java, o el intérprete GHC

    + +

    La programación OO tradicional permite y fomenta el uso de efectos. Los objetos responden a mensajes, eventualmente produciendo efectos, y son responsables tanto de generar como controlar estos efectos ordenando su ejecución y protegiendo su estado interno.

    + +

    La programación funcional en su forma más básica, en cambio, se trata de resolver los problemas en términos de aplicación de funciones puras, es decir, desprovistas de efecto. Entonces, si decimos que los efectos son necesarios, ¿que beneficio nos puede reportar la programación funcional?

    + +

    En primer lugar, porque que los programas con efectos son más difíciles de desarrollar y probar: los efectos no se ven en el código y no pueden ser trazados facilmente, a diferencia de un valor etiquetado, que es fácil de encontrar y predecir su comportamiento independientemente del lugar donde se encuentre. En un programa puro, si la expresión:

    + +

    objeto.mensaje(argumento) 

    + +

    resulta en la evaluación de f(objeto, argumento), entonces siempre la primera expresión puede ser reemplazada por la segunda (transparencia referencial). Como caso particular, a iguales argumentos, igual resultado. Además asegura que la evaluación de cualquier otra expresión no habrá sido modificada por esta. Ninguna de ambas afirmaciones son verdaderas en un programa con efectos.

    + +

    Diseñar un programa con efectos agrega entradas y salidas omnipresentes e invisibles; los datos viajan de forma global y las transformaciones ocurren en el tiempo. Su manejo se vuelve crítico cuando nuestro código se ejecuta en múltiples hilos, o ante la presencia de excepciones.

    + +

    Afortunadamente, aún es posible diseñar programas o partes de programas desprovistos de efectos, como parte de sistemas mayores: una calculadora, un compilador, un motor de reglas de un filtro de correo, son algunos de los infinitos programas que pueden ser modelados sin efecto.

    + +

    En OO existe una tendencia tendencia natural pero errada de forzar las responsabilidades y relaciones entre los objetos imiten a las del mundo real, perdiendo de vista que el objetivo de un sistema oo normalmente no se trata de simular sino resolver problemas, y en ocasiones las soluciones que se apartan de la realidad son igualmente simples de entender, y más fáciles de implementar y mantener. Esta malinterpretación lleva a que los objetos también presenten cambios de estado superficiales, aun cuando, como señalábamos antes, podrían haber realizado la misma tarea sin éste.

    + +

    La programación funcional entonces nos permite mejorar nuestros diseños de objetos, al eliminar los efectos innecesarios.

    + +

    En segundo lugar, porque aún en el uso de los efectos, es posible y en ocaciones desaeable un tratamiento a más alto nivel del los mismos. Una de las fortalezas de los objetos es su capacidad, comparada con la programación procedural, para la construcción efectos controlados y ordenados pero si bien triunfa al controlar la generación de efectos, falla al intentar separar su generación de su evaluación, al cual ocurre indefectiblemente en el mismo momento. La programación funcional nuevamente nos provee estrategias para cosificar (reificar) a los efectos, transformándolos en valores, y dandole el poder de controlar los efectos a incluso a aquellos objetos que no lo generaron.

    + +

    Ejemplo:

    + +

    snd  (putStr "", putStr "foo")

    + +

    Por último, una consecuencia interesante del asilamiento de los efectos es que conlleva una modularización del código

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/el-papel-del-diseno-en-la-metodologia-de-desarrollo.html b/wiki/articles/el-papel-del-diseno-en-la-metodologia-de-desarrollo.html new file mode 100644 index 0000000000..16392c2398 --- /dev/null +++ b/wiki/articles/el-papel-del-diseno-en-la-metodologia-de-desarrollo.html @@ -0,0 +1,470 @@ + + + + + + + + + + + El papel del diseno en la metodologia de desarrollo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + El papel del diseno en la metodologia de desarrollo +

    +
    + + + +
    +

    El diseño cumple un rol fundamental en todos los desarrollos de software. Es entonces cuando tenemos que tomar decisiones que afectan directamente al producto que vamos a construir. Por supuesto, el qué del análisis vs. el cómo del diseño es una diferencia que aparece en todos los libros. Pero mientras en el qué del análisis las recomendaciones generales apuntan a ordenar, clasificar, separar

    + +
      +
    • en lo que es parte del sistema
    • +
    • de lo que no lo es
    • +
    + +

    o bien, en encontrar los actores e identificar

    + +
      +
    • los requerimientos funcionales
    • +
    • y no funcionales
    • +
    + +

    o

    + +
      +
    • en discriminar requerimientos imprescindibles para la puesta en producción
    • +
    • de los importantes
    • +
    • o deseables
    • +
    + +

    en el diseño necesitamos echar mano a herramientas mucho más cercanas a la tecnología.

    + +

    Qué es diseñar

    + +

    Diseñar es encontrar:

    + +
      +
    • los componentes de un sistema
    • +
    • la responsabilidad de cada componente (que justifica su existencia)
    • +
    • y la relación que cada componente tiene con los demás (sea temporal o más permanente en el tiempo)
    • +
    + +

    Para eso tenemos que tomar decisiones, y aquí es donde empezamos a depender de la tecnología, porque ella nos define:

    + +
      +
    • sus abstracciones +
        +
      • ¿cómo modelo cada componente o entidad?
      • +
      • ¿cómo defino comportamiento? ¿puedo abstraer ese comportamiento?
      • +
      • ¿cómo relaciono las entidades? ¿debo distinguir el medio en donde esas entidades están relacionadas?
      • +
      +
    • +
    • sus limitantes
    • +
    • sus beneficios
    • +
    + +

    El diseño y la metodología

    + +

    Si la metodología de trabajo es secuencial, cada fase del proyecto tiene un comienzo y un fin específico. El diseño debe respetar el orden que le corresponde: después del análisis y antes de la programación / construcción. Si la metodología de trabajo es iterativa, esto implica diseñar en diferentes momentos, sin acotarlo a un período determinado.

    + +

    De la misma manera,

    + +
      +
    • cuando la metodología es orientada al proceso, se genera una gran cantidad de documentación respaldatoria del diseño. El proceso es el eje central del proyecto, que guía al objetivo que se quiere alcanzar (en el diseño esto se concreta con un documento entregable que es la especificación). Si el proceso está bien definido sólo hay que controlar el avance de las tareas.
    • +
    + + + +
      +
    • cuando la metodología es orientada al producto final, nos interesa más dejar en claro las decisiones importantes que respalden el software que está corriendo. La interacción entre las personas es fundamental y termina definiendo el proceso de diseño, de la misma manera que el éxito o el fracaso del mismo.
    • +
    + +

    Diseño anticipado y diseño iterativo

    + +

    La metodología de desarrollo nos lleva a diseñar de dos formas completamente diferentes:

    + +

    Las metodologías predictivas proponen el diseño anticipado, donde se asume que

    + +
      +
    • el análisis ya ha relevado todos los procesos que el usuario necesita
    • +
    • tenemos disponible toda la información para poder definir cada proceso
    • +
    • no habrá cambios en los requerimientos hasta nuestra implementación +
        +
      • el usuario no hará cambios o nuevos pedidos.
      • +
      • no habrá cambios externos al sistema que obliguen a modificarlo (como disposiciones legales).
      • +
      +
    • +
    • si el diseño es adecuado, la codificación se ajustará perfectamente a lo que el usuario necesita. +
        +
      • para ello hay que documentar el sistema en su completitud para que los programadores no tengan que tomar decisiones de diseño en la codificación.
      • +
      +
    • +
    • en la fase de diseño no se debe programar, dado que se estaría solapando la actividad (de la misma manera que en la fase de codificación no se debe diseñar)
    • +
    + +

    Por el contrario, las metodologías adaptativas proponen el diseño iterativo, donde se asume que

    + +
      +
    • sólo tenemos algunos procesos relevados, y aunque los tuviéramos en su totalidad, los requerimientos podrían cambiar.
    • +
    • es inocente pensar en que no habrá cambios en los requerimientos, dado que +
        +
      • el usuario no sabe exactamente lo que se va a construir y tiene derecho a pedir modificaciones cuando se da cuenta de que cometió un error al dar información al diseñador.
      • +
      • bajo la premisa anterior el diseñador no puede realizar un diseño que no esté sujeto a cambios, por los errores propios que además podría cometer.
      • +
      +
    • +
    • si el diseño no es adecuado, debemos cambiarlo lo más pronto posible. Esto incluye la fase de codificación.
    • +
    • si queremos reflejar la realidad, tenemos que permitir que haya alternancia entre diseño y programación. No paralelizamos las actividades, sino que una se va solapando a la otra, como en una pila.
    • +
    • el diseño iterativo considera que los errores son parte del desarrollo mismo y necesitamos poder modificar el diseño en cualquier momento, sin que eso paralice el proyecto (iterativo tiene mucho de “prueba y error”).
    • +
    + +

    Análisis comparativo

    + +

    Los defensores del diseño anticipado sostienen que en el diseño iterativo se pierde el orden, que es difícil de coordinar un proyecto (no se sabe exactamente en qué porcentaje está cumplida cada actividad), y que el diseño iterativo confunde diseño y programación, al punto en el que en realidad sólo se programa.

    + +

    Los defensores del diseño iterativo creen en que todos los proyectos se construyen de esta manera, lo único que hacemos al utilizar esta metodología es reflejar lo que sucede en la realidad: los requerimientos cambian (aparecen nuevos, se modifican los existentes y algunos incluso desaparecen durante el proyecto), los diseñadores se equivocan, también lo hace el usuario y continuamente nos vemos obligados a adaptar nuestra planificación. Separar un proyecto en varias iteraciones facilita aceptar esos cambios, porque no se mantienen fijos los requerimientos ni los diseños, solamente mantenemos el plazo de entrega (lo que vamos a entregar está sujeto a cambios en cada iteración).

    + +

    Pensar y hacer

    + +

    Al hacer la comparación entre las metodologías orientadas al producto vs. las orientadas al proceso y al ver la enorme diferencia entre el diseño predictivo y el iterativo, se pone sobre la mesa una larga discusión: ¿es correcto asociar los tiempos de diseño y programación a los tiempos donde se piensa y donde finalmente se hace? ¿es tan taxativa la diferencia? ¿puedo abstraer los detalles técnicos para diseñar una solución? ¿debe ocurrir primero la documentación y después la construcción o son tareas que pueden solaparse? ¿es necesario contar con dos perfiles diferenciados, o sea, un analista funcional y otro programador? ¿no sería más sano tener un desarrollador senior con mayores capacidades de abstracción y otro con menos experiencia, que pueda formarse en la materia?

    + +

    La metodología define la discusión filosófica de si nos interesan más las personas o los procesos. Asumir que el proceso tiene la prioridad presupone que sólo tengo recursos para asignar, y si divido perfiles en personas que piensan (diseñadores) de las que hacen o ejecutan (programadores) eso permite intercambiar gente sin mayores inconvenientes. Si pienso que las personas son importantes, que su grado de experiencia, la relación entre sí, la motivación personal y grupal, la capacidad de aprendizaje y la respuesta ante problemas que surgen son la clave de éxito de un proyecto, no nos interesa hacer la distinción entre pensar y hacer, porque esto ocurre todo el tiempo en forma simultánea, y mientras menos quiera disociar estos eventos (pensar y hacer) menos complicaciones tengo para encontrar un diseñador que sólo diseñe y un programador que sólo programe. Además el programador se transforma en una persona crítica del diseño, diseño que entonces puede mejorarse (es una metodología menos rígida en este sentido).

    + +

    Integración de las actividades de diseño en el proceso de desarrollo

    + +

    ¿Qué actividades ocurren al diseñar?

    + +
      +
    • Interactuamos con el usuario para repreguntar o proponer alternativas a lo que él solicitó
    • +
    • Interactuamos con el equipo de desarrollo, en donde pueden surgir +
        +
      • inconsistencias en las definiciones que no habíamos detectado antes: en el diseño iterativo este “inconveniente” está previsto, no así en el diseño anticipado en donde el equipo del proyecto debe asumir el costo de este imprevisto.
      • +
      • dificultades técnicas de implementación: esto suele ser más frecuente de lo que imaginamos, ya sea porque subestimamos la dificultad de un requerimiento, porque no tuvimos en cuenta algún factor tecnológico o porque los imprevistos suceden en todo proyecto.
      • +
      +
    • +
    + +

    Mientras que las metodologías secuenciales ven que el análisis condiciona el diseño y éste a su vez define las decisiones de implementación, es interesante notar que en los casos que mencionamos arriba es al revés: la arquitectura (o más general, las cuestiones técnicas) impactan sobre el diseño y el diseño puede hacer variar lo relevado en el análisis. De hecho, este es el valor agregado de un buen diseñador: hacer las preguntas que disparen mejoras en lo que el usuario pide.

    + + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/el-signo-pesos-en-haskell.html b/wiki/articles/el-signo-pesos-en-haskell.html new file mode 100644 index 0000000000..dadefbaf08 --- /dev/null +++ b/wiki/articles/el-signo-pesos-en-haskell.html @@ -0,0 +1,339 @@ + + + + + + + + + + + Uso del signo pesos ($) en haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Uso del signo pesos ($) en haskell +

    +
    + + + +
    +

    El signo pesos en Haskell (el $) se usa para 2 cosas:

    + +

    1- La función aplicar

    + +

    $ es la función “aplicar”. Hacer even $ 4 significa “al even aplicalo pasándole el 4”, o sea que es lo mismo que hacer even 4. Se suele usar para componer y hacer algunas cositas chetas como por ejemplo:

    + +

    Ejemplo, si en la consola quiero usar la función pam así:

    + +
    Prelude> pam 5 [even, even, odd]
    +[False, False, True]
    +
    + +

    Es decir, que de una lista de funciones quiero aplicarlas a un valor dado, podría resolverlo así:

    +
    pam :: a -> [(a -> b)] -> [b]
    +pam cosa funciones = map (\f -> f cosa) funciones
    +
    +-- otra forma:
    +-- pam cosa funciones = map (aplicarA cosa) funciones
    +-- aplicarA cosa funcion = funcion cosa
    +
    + +

    o bien aprovechar la función $:

    + +
    pam :: a -> [(a -> b)] -> [b]
    +pam cosa funciones = map ($ cosa) funciones
    +
    + +

    Ahí aprovechamos la aplicación parcial de $ (la aplicación parcial de la función aplicación 😆) para pasarle la cosa que necesita y luego que le falte recibir la función. Luego el map hace la magia de irle pasando todas las funciones de la lista.

    + +

    2- Evitando paréntesis

    + +

    La función$ tiene muy poca precedencia. Eso significa que a veces la gente la usa para evitar paréntesis.

    + +

    Por ejemplo, esto está mal:

    +
    even 2 * 3
    +
    +

    Porque even tiene más precedencia que el * , eso significa que va a hacer even 2 y luego multiplicarlo por 3, lo cual es error de tipos.

    + +

    Entonces, hay que poner paréntesis:

    +
    even (2 * 3)
    +
    +

    O bien usar el $ :

    +
    even $ 2 * 3
    +
    +

    Aprovechando que eso significa “al even aplicalo pasándole el 2*3”, y que como tiene muy poca precedencia, hace que todo lo que está a la izquierda se considere una cosa (el even), que todo lo que está a la derecha (el 2 * 3) se considere otra y entonces a even le aplica el resultado de 2*3.

    + +

    Es un clásico problema de sintaxis, de parsers. Cada lenguaje tiene sus reglas de precedencia para desambiguarlo, Haskell tiene las suyas, y se usa el $ como chiche a veces para evitar paréntesis.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/elementos-teoricos-para-comparar-tecnologias-de-presentacion.html b/wiki/articles/elementos-teoricos-para-comparar-tecnologias-de-presentacion.html new file mode 100644 index 0000000000..a52a9c71f1 --- /dev/null +++ b/wiki/articles/elementos-teoricos-para-comparar-tecnologias-de-presentacion.html @@ -0,0 +1,502 @@ + + + + + + + + + + + Elementos teoricos para comparar tecnologias de presentacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Elementos teoricos para comparar tecnologias de presentacion +

    +
    + + + +
    +

    Clientes livianos y pesados

    + +

    Introducción a los conceptos de cliente y servidor

    + +

    Si una aplicación es accedida por múltiples usuarios simultáneamente, probablemente cada uno de ellos lo haga desde su propia computadora en forma remota. Al programa que se ejecuta en la máquina del usuario se lo denomina cliente.

    + +

    Luego, esos clientes necesitarán poder compartir información entre sí; en muchos casos esa información se centralizará en una o más programas que se denominan servidor (en inglés server).

    + +

    La forma de repartir responsabilidades entre clientes y servidores dan lugar a un primer nivel de clasificación de las posibles arquitectura de una aplicación. Desde el punto de vista de la teoría de presentación, el punto más interesante será el cliente, ya que será el que tenga la responsabilidad de interactuar con el usuario.

    + +

    Clasificación tradicional

    + +

    Tradicionalmente se solía clasificar a los clientes entre pesados y livianos. Según esa clasificación, un cliente pesado tiene las siguientes características:

    + +
      +
    • Se instala en la máquina cliente.
    • +
    • Es un programa independiente y completo (en inglés stand alone, esto es, no requiere de la presencia previa de otros programas en la máquina en la que se va a ejecutar (como máquinas virtuales, intérpretes, application clients, etc).
    • +
    • Está pensado para ser utilizado en un entorno de ejecución específico (hardware, sistema operativo, etc) y eso le permite aprovechar todos sus recursos sin limitaciones. Por ejemplo: +
        +
      • Se pueden utilizar todos los periféricos de la máquina como ser impresoras o cualquier dispositivo específico.
      • +
      • No hay limitaciones en cuanto a las formas de presentar la información o de interactuar con el usuario.
      • +
      +
    • +
    • Contiene gran parte o toda la lógica de la aplicación, requiriendo pocos servicios del servidor, que se limita a ser un repositorio central de información.
    • +
    • Requiere grandes cantidades de recursos de la máquina cliente.
    • +
    + +

    Los clientes livianos se caracterizan por delegar gran parte de la lógica de la aplicación a la máquina servidora y de esa manera requerir menor cantidad de recursos de la máquina cliente. Sin embargo hay otra característica de un cliente liviano que cambia radicalmente la forma de pensar las aplicaciones y es la aparición del concepto de application client.

    + +

    El application client es un entorno en el cual se ejecutan las aplicaciones clientes de forma controlada, les da servicios que permiten simplificar la programación de las mismas y también tiene políticas que permiten proteger a la máquina de posible código malicioso. El application client más ampliamente conocido es el web browser, pero no es el único.

    + +

    La ejecución dentro de un application client tiene gran impacto sobre las aplicaciones construidas de esta manera:

    + +
      +
    • El application client se ocupa de obtener dinámicamente el código de la aplicación, eliminando la necesidad de instalación y de actualización de versiones.
    • +
    • La aplicación ya no es independiente y sólo puede ejecutarse en una máquina que contenga el application client correspondiente, esto nos lleva con frecuencia a no utilizar el application client que podría ser más útil a nuestros propósito sino a amoldarnos al que es más probable de encontrar instalado en las máquinas en las que querremos ejecutar nuestro programa.
    • +
    • Permite que la misma aplicación se ejecute en máquinas totalmente distintas, en tanto tengan el mismo application client.
    • +
    • Restringe las posibilidades de uso de la máquina a lo provisto por el application client. Por ejemplo en el caso de una aplicación web, tradicionalmente las aplicaciones estuvieron limitadas a la utilización del lenguaje HTML, lo que limitaba en gran medida las posibilidades de interacción con el usuario.
    • +
    + +

    Evolución de los tipos de cliente

    + +

    Con el tiempo la clasificación taxativa entre clientes pesados y livianos se fue diluyendo y fueron apareciendo opciones intermedias. Desde ambos lados fueron apareciendo herramientas que intentaban incorporar en uno de los mundos algunas de las ventajas del otro.

    + +

    Application Clients

    + +

    En un primer lugar la universalización del concepto de Virtual Machine o la popularización de diferentes lenguajes interpretados hace que sea difuso cuándo una aplicación es stand alone o está utilizando un application client. Por ejemplo, una aplicación Java puede verse como un cliente liviano que se ejecuta sobre un application cliente preinstalado (la JVM) o bien ver a ambos como un programa instalable único. En definitiva es una cuestión de como se distribuye el programa, ya que hoy en día no existen practicamente lenguajes que no requieran de un intérprete, máquina virtual o determinadas bibliotecas instaladas previamente para poder ejecutar programas.

    + +

    El cuadro se completa cuando se incorporan herramientas para actualizar código dinámicamente en lenguajes tradicionalmente pensados para aplicaciones pesadas como Java (Java WebStar).

    + +

    Inclusive la utilización de application clients se ha extendido a nuevos entornos, entre ellos podemos mencionar dos: Firefox y Eclipse, en ambos casos encontramos un entorno base o microkernel que provee de un entorno para la ejecución de aplicaciones y una arquitectura basada en plugins o add-ons, que son los que en última instancia dan forma a la aplicación.

    + +

    Rich Internet Applications

    + +

    Por otro lado la popularización de las aplicaciones en Internet se contrapone con la gran cantidad de limitaciones que impone el HTML como lenguaje base para modelar las interfaces de usuario de dichas aplicaciones. Eso fue dando lugar a la aparición de múltiples tecnologías que intentan sobreponerse a dichas limitaciones, algunos ejemplos son:

    + +
      +
    • La posibilidad de ejecutar JavaScript dentro del web browser permite tener comportamiento en el cliente que ya no se delega en el servidor.
    • +
    • Manipular los componentes visuales desde ese código JavaScript en el cliente, para salir de las limitaciones impuestas por el HTML.
    • +
    • La incorporación de tecnologías como AJAX permiten romper la metafora navegacional definida originalmente por el browser.
    • +
    + +

    Adicionalmente, la aparición de herramientas como Flash, Applets, SVGs y HTML5 incorporan nuevos application clients que rompen la visión original del browser-intérprete-de-HTML.

    + +

    A las aplicaciones que salen de las limitaciones de navegación, interacción y visuales que tenían las aplicaciones web tradicionales se las denomina Rich Internet Applications (RIA) y por extensión también a las tecnologías que permiten desarrollar ese tipo de aplicaciones (se podría sumar también JavaScript a esta lista). Si bien se podría decir que este tipo de ideas están aún en evolución, se observa una tendencia a tener application clients cada vez más poderosos.

    + +

    Uso de Recursos

    + +

    Tanto la aparición de applications clients cada vez más poderosos y complejos como la intención de agregar dinamismo y comportamiento a los clientes han producido un incremento considerable en la cantidad de recursos que requiere una aplicación web, habiendo en muchos casos prácticamente ninguna diferencia entre un cliente pesado y un cliente liviano.

    + +

    Descripción de la vista

    + +

    Otro de los elementos importantes a analizar al comparar tecnologías de presentación son las herramientas que cada tecnología propone al tiempo de definir una vista.

    + +

    Los conceptos fundamentales al describir una vista son los de componente y layout. Los componentes constituyen los elementos activos de la vista, es decir, aquellos con los que el usuario puede interactuar. El layout es la estrategia que indica cómo organizar los componentes espacialmente para poder visualizarlos.

    + +

    Si bien algunos frameworks modernos se denominan a sí mismos orientados a componentes se puede considerar que en realidad la amplia mayoría de las tecnologías de interfaz de usuario están constituidas por componentes. La diferencia está entonces en la forma de describir esos componentes y su disposición espacial, que se puede clasificar entre:

    + +

    Programática
    +Se basa en la manipulación directa en el programa de los componentes visuales que conforman la vista.

    + +

    Declarativa
    +En la que se utiliza un lenguaje de más alto nivel que describe características de la vista pero sin indicar el algoritmo para su construcción o sin manipular los componentes visuales directametne

    + +

    Visual
    +Que permite escojer los componentes de una paleta y visualmente organizarlos en la pantalla sin necesidad de programar o escribir prácticamente nada de código.

    + +

    Model driven
    +En la que la interfaz de usuario está guiada por el modelo de dominio y no se necesita programar específicamente (o se reduce notablemente la necesidad de programarla).

    + +

    Otra dimensión del análisis a realizar pasa por los bloques de construcción de que disponemos, por ejemplo:

    + +
      +
    • De qué componentes disponemos y si es posible agregar nuevos componentes.
    • +
    • Qué formas de layout están contempladas.
    • +
    • Qué mecanismos de interacción tiene el usuario predefinidos con esos componentes.
    • +
    + +

    Mecanismos de descripción

    + +

    Mecanismos programáticos

    + +

    Herramientas disponibles

    + +

    Componentes

    + +

    Hay un conjunto de componentes básicos que suelen estar disponibles en todas las tecnologías, que incluyen:

    + +
      +
    • Campos para ingresar texto, pueden ser de una línea o multilínea.
    • +
    • Selectores entre varias opciones (combos, option buttons, etc). Ṕueden ser de selección simple o múltiple.
    • +
    • Check boxes (para seleccionar o no una opción, combinando varios se puede formar un selector múltiple).
    • +
    • Diferentes variantes de botones.
    • +
    • Y otros controles informativos como ser labels o imágenes.
    • +
    + +

    Posibilidades de interacción

    + +

    También se deben analizar las posibilidades de interacción con esos elementos como por ejemplo:

    + +
      +
    • Qué eventos se pueden obtener de cada control, es decir, clickear sobre el control, modificar su valor, apretar una tecla, movimiento del mouse, etc.
    • +
    • Drag & drop.
    • +
    + +

    Layouts

    + +
      +
    • Fijo xy.
    • +
    • tabs
    • +
    + +

    Componentes

    + +
      +
    • Diferentes formas de describir una vista: programática, declarativa, visual, model driven. +
        +
      • Diferencias entre diferentes variantes de declaratividad, scriptlets, etc.
      • +
      • Manipulación de componentes vs. manipulación de texto.
      • +
      +
    • +
    + + + +
      +
    • Formas de navegación: pantallas y formularios, ventanas y diálogos (o SPI), manipulación directa. +
        +
      • Control de la iniciativa: usuario o aplicación.
      • +
      • Integración con el dominio de la aplicación: stateless (basada en servicios) o statefull (basada en objetos y en eventos).
      • +
      +
    • +
    + +

    Modelado

    + +
      +
    • Estado conversacional: en el cliente, en el server (sesión), en el pedido, en objetos específicos (por ejemplo: caso de uso).
    • +
    • Integración de la lógica: eventos y bindings (nivel de campo), formulario o pantalla (submit), objetos específicos (por ejemplo: caso de uso).
    • +
    • Arquitecturas: orientado a la presentación, datos, servicios, objetos.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/encapsulamiento.html b/wiki/articles/encapsulamiento.html new file mode 100644 index 0000000000..550994c80e --- /dev/null +++ b/wiki/articles/encapsulamiento.html @@ -0,0 +1,363 @@ + + + + + + + + + + + Encapsulamiento + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Encapsulamiento +

    +
    + + + +
    +

    ¿Qué es el encapsulamiento?

    + +

    Quien usa un objeto sólo ve lo que necesita para poder interactuar con él, que es el comportamiento que exhibe. Los detalles internos quedan encapsulados en el objeto. Así quedan acotadas y explicitadas las formas posibles de interactuar con un objeto.

    + +

    El ocultamiento de detalles de implementación, como ser los atributos de un objeto, permite separar mejor las responsabilidades y evitar efectos inesperados como resultado de la modificación del valor de las variables por entidades externas.

    + +

    El uso de setters y getters (mensajes para modificar y conocer el valor de un atributo respectivamente), también conocidos como accessors, es importante para que el objeto que tiene esos atributos pueda controlar el uso de los mismos y para que los que usan al objeto que los tiene no sufran un impacto muy grande si la implementación del mismo cambia.

    + +

    Ejemplo

    + +

    Supongamos que representamos a los lugares a los que puede volar nuestra amiga Pepita la golondrina como objetos que conocen su kilometraje en una ruta y nos saben decir a qué distancia se encuentran de otro lugar. Si su estado interno se modificara de modo que su ubicación se represente por una coordenada (x e y), sólo los lugares deberían verse afectados por este cambio ya que a Pepita sólo le interesa conocer la distancia entre dos lugares.

    + +

    A medida que el sistema crece esta característica toma más importancia ya que no es fácil determinar todos los lugares en los cuales algo se está usando y qué impacto tiene ese uso.

    + +

    Es importante entender que acceder a los atributos de un objeto mediante mensajes no es suficiente para afirmar que no se rompe el encapsulamiento del objeto. Supongamos que queremos calcular la distancia que tiene que volar pepita para llegar a otro lugar, es muy común ver cosas como:

    + +

    Smalltalk: +pepita lugarActual kilometraje - otroLugar kilometraje

    + +

    Wollok: +pepita.lugarActual().kilometraje() - otroLugar().kilometraje()

    + +

    (donde lugarActual y kilometraje son los getters de los respectivos objetos receptores) para trabajar con el número resultante en vez de delegar en el objeto que puede resolver el problema de la distancia a otro lugar. Si bien sólo se están usando getters, al preguntarle el kilometraje al lugar cuando lo que nos interesaba era la distancia nos estamos acoplando a cómo representa su ubicación, y por ende si se quisiera cambiar a coordenadas, los usuarios del mensaje kilometraje se van a ver afectados.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/entradas-al-proceso-de-diseno.html b/wiki/articles/entradas-al-proceso-de-diseno.html new file mode 100644 index 0000000000..0b7c9424fb --- /dev/null +++ b/wiki/articles/entradas-al-proceso-de-diseno.html @@ -0,0 +1,385 @@ + + + + + + + + + + + Entradas al proceso de diseno + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Entradas al proceso de diseno +

    +
    + + + +
    +

    Ralph & Wand definen que el diseño clasifica las entradas o influencias al proceso de diseño en requerimientos, objetivos, componentes primitivas, restricciones y entorno.

    + +

    Requerimientos

    + +

    Los requerimientos o requirements son la entrada más obvia y tal vez la más importante. La fuente de los requerimientos es el proceso de análisis, el análisis también es una especificación: de lo que el sistema debe ser, de sus características externas. El diseño especifica cómo el sistema debe construirse.

    + +

    La clasificación más común de los requerimientos es dividirlos entre funcionales y no funcionales. Una buena especificación de requerimientos debe contemplar tanto las cuestiones funcionales como las no funcionales, y el diseño deberá proponer ideas.

    + +

    Requerimientos funcionales

    + +

    Los requerimientos funcionales son las capacidades o funcionalidades de un sistema de software. Detallan el comportamiento del sistema. En otras palabras, lo que el sistema debe proveer. Hay distintos tipos de requerimientos no funcionales:

    + +

    Procesos de Negocio
    +Los procesos de negocios permiten especificar como un proceso se lleva a cabo a través de la organización, ya que requiere intervención de diferentes actores y áreas, en diferentes lugares y tiempos.

    + + + +

    Casos de Uso
    +Los caso de uso definen una interacción entre un actor y el sistema, para lograr un objetivo de negocio especifico en un lugar y momento especifico.

    + +

    Requerimientos no funcionales

    + +

    Son los que especifican la forma en que el sistema debe llevar a cabo esas capacidades, determinan la calidad con la que el sistema brinda los servicios o bien la calidad con la que está construido.

    + +

    Objetivos (goals)

    + +

    Ralph y Wand diferencian un subconjunto de los requerimientos denominados objetivos (goals). Los objetivos resumen el impacto esperado del sistema en el ambiente.

    + +

    Componentes primitivas (primitive components)

    + +

    Son los bloques de construcción provistos por la tecnología subyacente. En los niveles más bajos de abstracción del sistema, las abstracciones utilizadas tienden a coincidir con las herramientas provistas por la tecnología, tanto en cuanto a sus bloques primitivos de construcción, como en la forma de combinarlos entre sí.

    + +

    Restricciones

    + +

    Las restricciones o constraints pueden tener diferentes orígenes:

    + +
      +
    • Tecnológicas, tenemos que tener en cuenta qué cosas permite o no permite la tecnología en la que vamos a construir el sistema.
    • +
    • Leyes y otros reglamentos, incluyendo a los reglamentos internos de la empresa o licencias de las herramientas que usamos.
    • +
    • Negocio, el negocio puede imponer restricciones de tiempo de llegada al mercado, costos y beneficios, tiempo de vida del sistema, entre otras.
    • +
    • De arquitectura, la arquitectura puede imponer restricciones de integridad, correctitud, completitud, constructibilidad o robustez, entre otras.
    • +
    + +

    Entorno (Environment)

    + +

    Nos interesa tanto el entorno tecnológico (con qué tecnología contamos) como social (características de las personas que intervienen). Podemos diferenciar dos entornos:

    + +

    Entorno de desarrollo
    +Es el ambiente en el que se diseña, construye y/o prueba el sistema.

    + +
      +
    • Desde el punto de vista social debemos tener en cuenta sus conocimientos previos en cuanto a herramientas tecnológicas, conceptuales y metodológicas. Por ejemplo, antes de introducir una tecnología nueva puede ser una buena idea analizar la capacidad del equipo para aprenderla.
    • +
    • Desde el punto de vista tecnológico debemos tener en cuenta por ejemplo los equipos con los que contamos para trabajar, si están todos en un mismo lugar o separados, si la comunicación (redes) entre esos lugares es buena o mala, si tenemos licencias de los programas que queremos usar, etc.
    • +
    + +

    Entorno de uso
    +El entorno en el que se usa el sistema.

    + +
      +
    • Desde el punto de vista social debemos considerar al usuario que esperamos, por ejemplo al diseñar la interfaz de usuario, o para instalarse el sistema en caso de ser necesario, sus costumbres previas, otros sistemas que usa.
    • +
    + +

    :*Desde el punto de vista tecnológico podemos considerar el hardware del que puede disponer el usuario, su conección a Internet, etc.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/errores-comunes--usar-un-predicado-como-si-fuera-una-variable.html b/wiki/articles/errores-comunes--usar-un-predicado-como-si-fuera-una-variable.html new file mode 100644 index 0000000000..de31c6dabd --- /dev/null +++ b/wiki/articles/errores-comunes--usar-un-predicado-como-si-fuera-una-variable.html @@ -0,0 +1,429 @@ + + + + + + + + + + + Errores comunes usar un predicado como si fuera una variable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Errores comunes usar un predicado como si fuera una variable +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    A veces se utilizan predicados unarios para representar verdades globales (lo que en otro paradigma sería una constante global).

    + +

    Por ejemplo podemos tener un predicado que nos diga la fecha de hoy:

    + +
    +
    +
    +      hoy(fecha(2009, 10, 15)).
    +
    +    
    +
    +
    + +

    O podemos tener un predicado que refleje el estado del tablero en un dominó:

    + +
    +
    +
    +      estado([ficha(0,1),ficha(1,4),ficha(4,2),ficha(2,2),ficha(2,5)]).
    +
    +    
    +
    +
    + +

    El error consiste en utilizar hoy o estado como si fueran constantes, y no lo son.

    + +

    Ejemplo 1 - Fecha de hoy

    + +

    Suponiendo que tengo en la base de conocimientos información sobre los downloads que se hicieron el día de hoy, en el predicado que relaciona un usuario, con un archivo bajado y una fecha; una forma incorrecta de utilizarlo sería:

    + +
    +
    +
    +      bajoAlgunArchivoHoy(Usuario):-
    +  download(Usuario, _Archivo, Fecha), Fecha = hoy. %INCORRECTO!
    +
    +    
    +
    +
    + +

    La forma correcta de hacerlo podría ser:

    + +
    +
    +
    +      bajoAlgunArchivoHoy(Usuario):-
    +  download(Usuario, _Archivo, Fecha), hoy(Fecha). 
    +
    +    
    +
    +
    + +

    Se ve que en la nueva versión, hoy se utiliza como predicado y no como individuo.

    + +

    Ejemplo 2 - Estado del dominó

    + +

    Si quiero saber los extremos de la lista que representa el estado del juego, es incorrecto hacer cosas como:

    + +
    +
    +
    +      extremo(E):-estado = [E|_].         %INCORRECTO!!
    +extremo(E):-ultimoLista(E, estado). %INCORRECTO!!
    +
    +    
    +
    +
    + +

    La forma correcta de hacerlo sería:

    + +
    +
    +
    +      extremo(E):-estado([E|_]).
    +extremo(E):-estado(Estado), ultimoLista(E, Estado).
    +
    +    
    +
    +
    + +

    Asumiendo que el predicado relaciona a una lista con su último elemento.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/errores-comunes-al-comenzar-a-trabajar-con-haskell.html b/wiki/articles/errores-comunes-al-comenzar-a-trabajar-con-haskell.html new file mode 100644 index 0000000000..19d0e7ef9e --- /dev/null +++ b/wiki/articles/errores-comunes-al-comenzar-a-trabajar-con-haskell.html @@ -0,0 +1,417 @@ + + + + + + + + + + + Errores comunes al comenzar a trabajar con haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Errores comunes al comenzar a trabajar con haskell +

    +
    + + + +
    +

    Variables mágicas

    + +

    Algo que se ve mucho en los parciales es gente que inventa variables mágicas por no entender orden superior y aplicación parcial, por ejemplo hacer algo como:

    + +

    aprobados alumnos = filter (nota alumno > 4) alumnos

    + +

    en vez de:

    + +

    aprobados alumnos = filter ((>4).nota) alumnos

    + +

    o en todo caso usando Expresiones lambda:

    + +

    aprobados alumnos = filter (\alumno -> nota alumno > 4) alumnos

    + +

    La variable alumno de la solución errónea no existe, y si existiera estaríamos cayendo en el problema explicado en la siguiente sección.

    + +

    Funciones y valores

    + +

    Es importante diferenciar:

    + +
      +
    • Qué valores son funciones y qué valores no.
    • +
    • En qué lugares se espera poner una función y en qué lugares se espera otro tipo de valor.
    • +
    + +

    Por ejemplo

    + +

    sonTodasPasables pelicula = all (puntajePromedio pelicula > 6) (snd pelicula)

    + +

    tiene un error porque la función espera como parámetro una función, mientras que no es una función (denota un valor booleano).

    + +

    _ Otro ejemplo:

    + +

    puntajes pelicula = snd pelicula +esRiesgosa = elem 1 puntajes

    + +

    ¿Cuál es el problema? La función espera como segundo parámetro una lista, sin embargo la expresión no es una lista, sino una función que devuelve una lista.

    + +

    Moraleja:

    + +
    +

    No es lo mismo un booleano/entero/string/etc que una función que devuelve un booleano/entero/string/etc

    +
    + +

    Composición y aplicación parcial

    + +

    Muchas veces se ven errores que (a veces disfrazados de un me confundí con los paréntesis) llevan a expresiones inválidas, lo importante es entender qué construcciones son válidas y cuáles no.

    + +

    Normalmente hay muchas formas de llegar al mismo resultado. Por ejemplo:

    + +

    (not.esDivisor año) 100 +not (esDivisor año 100)

    + +

    Estas dos lineas producen el mismo resultado. Mientras que las siguientes están mal:

    + +

    not.esDivisor año 100 +(not.esDivisor) año 100 +(otroBooleano && (not.esDivisor año)) 100

    + +

    Porqué? Repasemos las que estaban bien:

    + +

    (not.esDivisor año) 100

    + +

    Lo que está resaltado es una función. Es resultado de componer otras dos funciones: not y esDivisor año. Notá como me refiero a esDivisor año como una única función, que NO es esDivisor. Para ver que son diferentes, podemos solo chequear sus tipos:

    + +

    '''esDivisor::Int->Int->Bool +esDivisor año::Int->Bool'''

    + +

    Esta es una versión simplificada del tipo, no es exactamente lo que diría haskell, pero a efectos de la explicación da igual. Notá que esDivisor año espera un argumento menos que esDivisor (justamente, porque ya le pasaste el año). Obviamente, si aplicamos esta función otra vez, esto se repite.

    + +

    esDivisor año 100 :: Bool

    + +

    Esto ya no es una función. Es un booleano. Ya no puedo aplicarlo.

    + +

    Habiendo entendido esto, miremos otra vez la composición:

    + +

    (not.esDivisor año)

    + +

    Si digo que se está componiendo not con esDivisor año, podés deducir que la aplicación de una función tiene “mayor precedencia” que la composición. Una forma de entender esto es que la aplicación tiene prioridad, entonces la composición va a trabajar con el resultado de la aplicación.

    + +

    Comparemos esto con uno de los casos de error:

    + +

    (not.esDivisor año) 100      <- Funciona bien. Le aplico 100 al resultado de la composición +not.esDivisor año 100        <- Falla! Trata de componer not con esDivisor año 100, que es un Bool, no una función.

    + +

    Los otros casos erroneos también podemos deducirlos así:

    + +

    (not.esDivisor) año 100      <- Falla porque tratás de componer esDivisor, que espera más de un argumento. +(otroBooleano && (not.esDivisor año)) 100   <- Falla porque (not.esDivisor año) es una función y && espera un booleano.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/errores-comunes-con-select--y-collect-.html b/wiki/articles/errores-comunes-con-select--y-collect-.html new file mode 100644 index 0000000000..19637fe28c --- /dev/null +++ b/wiki/articles/errores-comunes-con-select--y-collect-.html @@ -0,0 +1,368 @@ + + + + + + + + + + + Errores comunes con select y collect + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Errores comunes con select y collect +

    +
    + + + +
    +

    Orden incorrecto entre collect: y select:

    + +

    Como se explica en Mensajes de colecciones, el select: es para filtrar una colección en base a un criterio mientras que el collect: es para recolectar los resultados de enviar un mensaje a cada objeto de la colección original.

    + +

    Supongamos que queremos obtener una colección con los promedios de los alumnos que aprobaron, podríamos plantearlo como

    + +

    (alumnos select: [:unAlumno | unAlumno aprobo ]) collect: [:unAlumno | unAlumno promedio ]

    + +

    Si en vez de eso hicieramos

    + +

    (alumnos collect: [:unAlumno | unAlumno promedio ]) select: [:unAlumno | unAlumno aprobo ]

    + +

    Esto no va a funcionar, porque el collect: va a retornar una lista de números, no de alumnos, con lo cual el filtrado no se va a poder hacer.

    + +

    Si lo que queremos es en cambio obtener los promedios > 4 de los alumnos, ahí no habría problema en hacer primero el collect: y luego el select:, porque el filtrado se haría sobre promedios y no sobre alumnos:

    + +

    (alumnos collect: [:unAlumno | unAlumno promedio ]) select: [:unPromedio | unPromedio > 4 ]

    + +

    Inicialización inecesaria de variables

    + +

    Fíjense una cosa: siempre que yo hago….

    + +

     a := cualquier cosa

    + +

    Eso es una asignación “destructiva”… sí ya sé, lo dije mil veces, pero lo que parece hasta acá fácil después igual genera confusiones.

    + +

    ¿Qué quiere decir eso de “destructiva”? Que se pierde lo que fuera que estaba referenciando la variable a, se pierde, o sea… no me importa lo que tenía la variable a antes de eso.

    + +

    ¿Por qué saco a colación esto ahora? Bueno el error que yo veo frecuentemente es este:

    + +

     a := Set new. + a := otroSet collect: [... etc]

    + +

    ¿Tiene sentido inicializar la variable a antes del collect:? Y no… si yo en la siguiente línea voy a hacer una asignación destructiva… justamente lo que sea que tiene la variable a se va a perder.

    + +

    Visto de otra manera, acuérdense que dijimos el collect: me devuelve una colección NUEVA. Es decir, que no usa el valor de la variable a… porque me devuelve una colección nueva.

    + +

    Y digo más, si entendés la asignación, podés ver que primero se evalúa el “lado derecho” (lo que está después del :=), y luego se asigna. Entonces “a” no interviene para nada en la evaluación de “ otroSet collect: [… etc] “ (salvo claro que aparezca a en la expresión). Digo esto para desmitificar la idea de que de alguna manera el collect: podría dejar sus valores en el Set que apunta la variable “a”… claramente eso no es posible.

    + +

    (Esa confusión puede que venga de programar en c, donde a veces yo necesito “alocar memoria” para que otro procedimiento deje datos en esa memora… bueno, acá no es necesario alocar memoria, eso pasa solo! wiii! jaja. Además que aún en estructurado para que el proc pueda usar lo que yo “aloqué” debería pasárselo por parámetro y no como valor de retorno, esa característica sí es compartida.)

    + +

    Obviamente, el ejemplo del collect: vale para select: y todo método que devuelva una colección. ¿No?

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/errores-comunes.html b/wiki/articles/errores-comunes.html new file mode 100644 index 0000000000..1fc55a7983 --- /dev/null +++ b/wiki/articles/errores-comunes.html @@ -0,0 +1,320 @@ + + + + + + + + + + + Errores comunes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Errores comunes +

    +
    + + + +
    +

    Contenido del tag “web-app”

    + +

    The content of element type "web-app" must match +"(icon?,display-name?,description?,distributable?,context-param*, +filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*, +taglib*,resource-env-ref*,resource-ref*,security-constraint*,login-config?,security-role*,env-entry*,ejb-ref*,ejb-local-ref*)".

    + +

    El mensaje quiere decir que el contenido web-app es inválido, está mal formado.

    + +

    Para entender el mensaje, en la lista entre paréntesis están los posibles tags “hijos” de webapp, para solucionarlo habría que fijarse si tienen algo que esté dependiendo de web-app y que no se ajuste a esa lista.

    + +

    Además:

    + +
      +
    • Tienen que estar en el orden que están en esa lista.
    • +
    • Los que tienen ? son opcionales pero pueden 0 o una veces,
    • +
    • los que tienen * pueden estar 0 o más veces.
    • +
    + +

    Un error muy común podría ser al tener varios servlets poner cada servlet con su servlet mapping y el estándar exige poner primero todos los servlets y recién después todos los servlet mappings.

    + +

    En este caso puntual, es muy posible tener esa validación en algún editor y que la aplicación funcione de todas maneras, porque el tomcat no es estricto al chequear el formato del web.xml. La recomendación es de todas formas ajustarse al estándar.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/errores-en-haskell.html b/wiki/articles/errores-en-haskell.html new file mode 100644 index 0000000000..478dfa1712 --- /dev/null +++ b/wiki/articles/errores-en-haskell.html @@ -0,0 +1,329 @@ + + + + + + + + + + + Errores en haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Errores en haskell +

    +
    + + + +
    +

    Ver Paradigma_Funcional

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/errores-frecuentes-al-programar-en-logico.html b/wiki/articles/errores-frecuentes-al-programar-en-logico.html new file mode 100644 index 0000000000..ac5c4d16ad --- /dev/null +++ b/wiki/articles/errores-frecuentes-al-programar-en-logico.html @@ -0,0 +1,427 @@ + + + + + + + + + + + Errores frecuentes al programar en logico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Errores frecuentes al programar en logico +

    +
    + + + +
    +

    Errores conceptuales más importantes

    + +
      +
    • Confundir los conceptos del paradigma, por ejemplo: +
        +
      • predicados con funciones - los predicados no devuelven cosas, tienen valor de verdad. Tenerlo en cuenta para la cantidad de parámetros y para no consultarlos mal
      • +
      • variables con individuos (en particular átomos) - sólo escriban variables con mayúscula!
      • +
      • predicados con individuos
      • +
      +
    • +
    • Errores lógicos propiamente dichos: + +
    • +
    • Estilos de programación no lógicos, por ejemplo: + +
    • +
    • Programación “con efectos colaterales”, por ejemplo intentos de “asignar” más de una vez un valor una misma variable.
    • +
    • Falta de abstracción, que puede verse reflejada en: +
        +
      • Uso de trucos programáticos de bajo nivel, en lugar de representaciones abstractas de alto nivel.
      • +
      • Ausencia de predicados auxiliares que abstraigan conceptos reutilizables en diferentes predicados de alto nivel (lo que normalmente lleva a la repetición de código).
      • +
      • Malas deciciones a la hora de separar un predicado en subtareas, que llevan a tener predicados auxiliares que no representan abstracciones o conceptos útiles.
      • +
      +
    • +
    • Problemas de inversibilidad; ya sea por falta de generación o por hacerlo incorrecta-/innecesariamente.
    • +
    + +

    Problemas generales de programación

    + +
      +
    • Incumplimiento de las consignas.
    • +
    • Código que no se entiende, desprolijo, desordenado.
    • +
    • Inconsistencias en general, por ejemplo: +
        +
      • Las diferentes reglas de un predicado esperan parámetros con significados distintos.
      • +
      • Una misma variable utilizada con diferentes objetivos inconsistentemente.
      • +
      +
    • +
    + +

    Errores más técnicos

    + +
      +
    • Mal uso del pattern matching, en dos versiones: +
        +
      • No aprovecharlo para quedarse con una parte de una estructura más grande (functor o lista).
      • +
      • Usar patrones demasiado específicos, perdiendo la oportunidad de construir predicados polimórficos.
      • +
      +
    • +
    • Usar igualdad (=) en lugar de is. -> Explicación: el = no resuelve cuentas. Es la igualdad más trivial, la igualdad visual y directa de patrones y átomos.
    • +
    • Usar el símbolo = en lugar de la misma variable, ó del individuo correspondiente.
    • +
    + +

    Cuestiones de estilo

    + +
      +
    • No elegir buenos nombres para variables y/o predicados.
    • +
    • Utilizar pasos intermedios innecesarios que no aportan a la claridad del código.
    • +
    • No utilizar variables anónimas donde corresponde.
    • +
    • Complejidad innecesaria.
    • +
    + +

    Carteles de Error del SWI-Prolog

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/escribiendo-un-paper.html b/wiki/articles/escribiendo-un-paper.html new file mode 100644 index 0000000000..ec2427e850 --- /dev/null +++ b/wiki/articles/escribiendo-un-paper.html @@ -0,0 +1,325 @@ + + + + + + + + + + + Escribiendo un paper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Escribiendo un paper +

    +
    + + + +
    +

    Un paper es un artículo de difusión científica. Dado el caracter científico del paper, la comunidad científica establece (quizás un poco ad-hoc) una cierta estructura y formato de estructura. En este artículo vamos a tratar la escritura de papers con un formato de tendencia _formal_.

    + +

    Para quienes quieran tener una breve introducción, recomiendo vean el siguiente video:

    + +

    En inglés: https://www.youtube.com/watch?v=g3dkRsTqdDA Slides

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/esquemas-de-tipado.html b/wiki/articles/esquemas-de-tipado.html new file mode 100644 index 0000000000..1ca51d2caf --- /dev/null +++ b/wiki/articles/esquemas-de-tipado.html @@ -0,0 +1,458 @@ + + + + + + + + + + + Esquemas de tipado + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Esquemas de tipado +

    +
    + + + +
    +

    Introducción

    + +

    ¿Qué es un tipo?

    + +

    Toda expresión en un programa puede denotar diferentes valores en diferentes momentos (dependiendo del lenguaje eso puede ocurrir en la misma o en diferentes ejecuciones del programa). Un tipo describe un conjunto de valores. Al asignarle un tipo a una expresión se está delimitando cuál es el conjunto de valores que podría denotar esa expresión.

    + +

    Por otro lado, las operaciones computacionales en general no pueden ser aplicadas sobre cualquier valor. Un sistema de tipos me provee una forma de estudiar qué valores tienen sentido para ser utilizados en una operación dada. Por ejemplo, si x e y son valores numéricos, la expresión x + y tiene sentido. En cambio si x e y son valores booleanos, x + y carece de sentido.

    + +

    La idea de tipo nos permite relacionar:

    + +
      +
    • un conjunto de valores que tienen ese tipo o son de ese tipo,
    • +
    • con las operaciones que pueden ser realizadas sobre esos valores.
    • +
    + +

    Sistemas de tipos

    + +

    Existen diferentes tendencias en cuanto a cómo se clasifican a los diferentes lenguajes en función de la presencia o no de un sistema de tipos o de las características de ese sistema de tipos. Diferentes autores hablan de lenguajes tipados o no tipados, fuerte o débilmente tipados, lenguajes estáticos o dinámicos. Intentaremos proveer una forma de categorización que sea amplia para poder estudiar diferentes lenguajes y autores.

    + +

    Según Luca Cardelli un lenguaje tipado es el que asocia cada expresión con un tipo (con uno no trivial). El sistema de tipos es el componente que administra la información de tipos de un programa. Un lenguaje se considera tipado por la existencia de un sistema de tipos, independientemente de que la sintaxis del lenguaje incorpore información de tipos.

    + +

    Los objetivos de un sistema de tipos son:

    + +
      +
    • Ayudar a detectar errores al programar.
    • +
    • Guiar al programador sobre las operaciones válidas en un determinado contexto, tanto en cuanto a documentación com en cuanto a ayudas automáticas que puede proveer por ejemplo un IDE.
    • +
    • En algunos casos el comportamiento de una operación puede variar en función del tipo de los elementos involucrados en la misma. De esto vamos a diferenciar varios sabores: polimorfismo, sobrecarga, multimethods, etc.
    • +
    + +

    Algunas características de un sistema de tipos:

    + +
      +
    • Proveen información al programador, de forma más precisa que un comentario.
    • +
    • Según Cardelli, un sistema de tipos debería permitir hacer validaciones utilizando la información de tipos, algorítmicamente.
    • +
    • Las validaciones basadas en un sistema de tipos, que son más fácilmente automatizables que otros tipos de especificaciones formales.
    • +
    + +

    Tipado implícito o explícito

    + +

    El tipado de Java es explícito, esto se ve en dos aspectos:

    + +
      +
    • Toda variable, parámetro, método tiene un tipo definido.
    • +
    • Para que dos objetos puedan ser polimórficos tengo que indicarlo explícitamente: herencia o interfaces.
    • +
    + +

    Las interfaces cumplen dos funciones:

    + +
      +
    • Permitir un polimorfismo chequeado estáticamente y no restringido por la herencia simple.
    • +
    • Ponerle nombre a un concepto que no quiero representar con una clase: documentar.
    • +
    + +

    En Smalltalk no necesito hacer una indicación explícita de que dos objetos sean polimórficos, basta con que entiendan algún(os) mensaje(s) en común. Vemos el ejemplo de los bloques y los símbolos.

    + +

    Chequeos estáticos y dinámicos

    + +

    Algunos ejemplos de cómo se comportan los tipos en Java y en Smalltalk

    + +
      +
    • En Java tomamos un String e intentamos mandarle el mensaje “caminar”, no compila: chequeo estático.
    • +
    • En Smalltalk hago lo mismo y me permite ejecutarlo, se rompe en tiempo de ejecución: chequeo dinámico o en tiempo de ejecución.
    • +
    + +

    Eso nos marca una primera categorización de los tipos: en función de en qué momento se chequean. No necesariamente un lenguaje tiene siempre el mismo comportamiento, en java si yo casteo postergo el chequeo hasta el tiempo de ejecución. Si se acuerdan de lenguaje C, recordamos que ante un casteo puede pasar cualquier cosas: a veces simplemente no se valida nada.

    + +

    Esta primera diferencia parecería volcar la balanza a favor de los lenguajes con chequeo estático, porque detectan antes los problemas, sin embargo vamos a ver que también tienen desventajas. Por otro lado, ante la presencia de casteos el chequeo estático se pierde.

    + +

    Finalmente es importante diferenciar entre chequeo dinámico y no chequeo. El chequeo dinámico me permite manejar el problema y manejarlo o por lo menos me lo informa correctamente, la ausencia de chequeo suele causar errores muy difíciles de detectar o corregir.

    + +

    Detección de errores

    + +

    Cardelli propone discriminar dos tipos de errores que se pueden producir durante la ejecución de un programa:

    + +

    Trapped (atrapados)
    +Son los errores que se detectan inmediatamente, por ejemplo una división por cero.

    + +

    Untrapped (no atrapados)
    +Son errores que pueden no ser detectados. El programa podría continuar ejecutándose por un tiempo antes de detectar el problema. Esto puede ocurrir en algunos lenguajes por ejemplo si se accede a posiciones de un array más allá de su longitud o se salta a una posición inválida de memoria.

    + +

    Un programa se considera seguro (safe) si no causa untrapped errors. Un lenguaje se considera seguro si todo programa escrito en ese lenguaje está excento de untrapped errors.

    + +

    En todo lenguaje se puede designar un conjunto de los errores como prohibidos. Los errores prohibidos deberían incluir a todos los errores untrapped, más un subconjunto de los errores trapped. Un programa que no causa errores prohibidos se dice que tiene buen comportamiento (good behavior).

    + +

    En un lenguaje strongly checked, todos los oprogramas tienen buen comportamiento, es decir:

    + +
      +
    • No ocurren errores untrapped.
    • +
    • No ocurren los errores trapped que se consideran prohibidos.
    • +
    + +

    Siempre queda a responsabilidad del programador evitar los errores trapped que no se eligieron como prohibidos.

    + +

    Tipos nominales y estructurales

    + +

    Eso nos lleva a una clasificación más: tipos estructurales vs. tipos nominales. Llamamos nominales a los tipos que tienen un nombre. En Java los tipos son nominales están dados por las clases (concretas o abstractas) y por las interfaces. En Smalltalk los tipos son estructurales, por ejemplo todos los objetos que entienden #value son un tipo. La nominalidad del Java se ve en que si hago dos interfaces con los mismos mensajes, los objetos que implementan la primera no son polimórficos con los objetos que implementan la segunda.

    + +

    Algunas combinaciones posibles

    + +

    Suele haber una fuerte relación entre los tipos nominales-explícitos y estructurales-implícitos. Esto es porque uno para explicitarlos le pone nombre, pero en algunos lenguajes como Scala existen tipos estructurales y explícitos.

    + +

    También suele haber una fuerte relación entre el chequeo estático y el tipado explícito o nominal, sin embargo en Haskell podemos ver que tenemos tipos implícitos y chequeo estático. Normalmente esto va asociado a un concepto llamado “inferencia de tipos”, es decir, ¿cómo se hace para poder chequear el tipo de algo sin que me lo digas? Tiene que poder inferirlo el compilador por sí mismo.

    + +

    Y acá se ven las desventajas de los sistemas de tipado más “fuertes”:

    + +
      +
    • Obligan a la burocracia de decir de qué tipo va a ser cada cosa y de indicar qué cosas pueden ser polimórficas.
    • +
    • Muchas veces me restringen las posibilidades que tengo al programar.
    • +
    + +

    Gran parte del trabajo en sistemas de tipos que se hace intenta construir sistemas o lenguajes que puedan evitar errores minimizando la burocracia y/o eliminando las restricciones innecesarias.

    + +

    Clasificaciones

    + +

    En resumen planteamos tres clasificaciones:

    + +
      +
    1. En cuanto a la forma de chequeo puede ser estático/compile time, dinámico/runtime o nada.
    2. +
    3. En cuanto a la forma de especificar el tipo de algo puede ser explícito o implícito / inferido.
    4. +
    5. En cuanto a la forma de constituir un tipo puede ser nominal o estructural (no sé si agregar dependientes, también hay más variantes).
    6. +
    + +

    Más complicada es la clasificación en cuanto a los tipos de polimorfismo que se banca (en particular en los lenguajes con tipado estático).

    + +

    Algunos ejemplos

    + +
      +
    • Java tiene un tipado estático, nominal y explícito (en presencia de casteos se vuelve dinámico)
    • +
    • Smalltalk es dinámico, estructural e implícito.
    • +
    • Self lo mismo.
    • +
    • Haskell es estático pero se banca ser explícito o implícito (inferencia de tipos) y en algunos casos también se comporta estructuralmente.
    • +
    • Scala es estático, tiene algo de inferencia y también soporta tipos estructurales y nominales.
    • +
    • ObjectiveC puede ser estático o dinámico si usas los ids.
    • +
    • C aparenta ser estático, pero ante casteos yo veo que el tipado es nulo.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/estado--identidad-y-diseno.html b/wiki/articles/estado--identidad-y-diseno.html new file mode 100644 index 0000000000..e603439806 --- /dev/null +++ b/wiki/articles/estado--identidad-y-diseno.html @@ -0,0 +1,321 @@ + + + + + + + + + + + Estado identidad y diseno + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Estado identidad y diseno +

    +
    + + + +
    +

    Inmutable vs mutable

    + +

    Decimos que un objeto es inmutable cuando su estado es insignificante, o se mantiene constante a lo largo de su ciclo de vida, o, en una visión más relajada, luego de su momento de ínstanciación.

    + +

    Identidad

    + +

    En el paradigma de objetos, estos componentes agrupan lo que en otros paradigmas en general está claramente separado: datos (estado) y comportamiento. Además, los entornos de objetos los manejan mediante referencias (C++ es una excepción notable), lo que nos lleva a otra propiedad fundamental: la identidad.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/estado-y-diseno.html b/wiki/articles/estado-y-diseno.html new file mode 100644 index 0000000000..76d5483856 --- /dev/null +++ b/wiki/articles/estado-y-diseno.html @@ -0,0 +1,302 @@ + + + + + + + + + + + Estado y diseno + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Estado y diseno +

    +
    + + + +
    +
      +
    1. REDIRECCIÓN Estado, Identidad y diseño
    2. +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/estereotipos-de-objetos.html b/wiki/articles/estereotipos-de-objetos.html new file mode 100644 index 0000000000..b55ae624d4 --- /dev/null +++ b/wiki/articles/estereotipos-de-objetos.html @@ -0,0 +1,396 @@ + + + + + + + + + + + Estereotipos de objetos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Estereotipos de objetos +

    +
    + + + +
    +

    Un objeto presenta presentan tres características fundamentales:

    + +
      +
    • Comportamiento: un objeto sabe hacer cosas, y eventualmente cada uno las podría saber hacer de distinta forma.
    • +
    • Estado: un objeto mantiene relaciones con otros objetos, las cuales pueden cambiar a lo largo de su vida. Muchas veces, al compararlo con paradigmas donde dato y operación son elementos claramente separados, es útil pensar al estado como justamente la parte de datos.
    • +
    • Identidad: un objeto es tratado mediante referencias, y puede ser distinguido de otro, aun cuando el otro presente el mismo estado y comportamiento.
    • +
    + +

    Los objetos existen en nuestro sistema para cumplir responsabilidades. Aunque normalmente asociamos fuertemente la idea de responsabilidad a la de comportamiento hay ocasiones en que nos convendrá diseñar nuestros objetos de forma tal que expongan su estado e identidad.

    + +

    En base a estos tres aspectos del objeto, podemos ensayar la siguiente caracterización de los objetos:

    + +
      +
    • Entidades: Su identidad es importante (cuando tenemos que enviarle varios mensajes a uno de estos objetos, nos importa que el receptor sea siempre el mismo, y no tan solo uno parecido). Presentan estado significativo y mutable, y poco comportamiento, fuertemente acoplado a las características anteriores. Su cíclo de vida es típicamente largo. Son ejemplos típicos de entidades aquellos objetos persistentes en una base de datos transaccional (aunque por motivos de implementación, su identidad nativa puede perder algo de importancia, y se recurre al uso de atributos que modelan la identidad).
    • +
    • Símbolos: Su identidad es importante, no presentan comportamiento más que la comparación por identidad (==) o quizás la representación textual (toString). No presentan estado, o es inmutable. Se los emplea típicamente para modelar códigos, o elementos del metamodelo del lenguaje, como nombres de clases o selectores. Algunos lenguajes como Smalltalk o Ruby soportan nativamente estos objetos, mientras que en otros, como Java, se suple su falta con Strings
    • +
    • Valores
    • +
    • Servicios/Tareas: aquellos objetos con una fuerte carga de comportamiento independiente de su estado
    • +
    • Objetos anémicos/DTO’s
    • +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    EstereotipoIdentidadComportamientoEstado
    EntidadImportanteMuchoMucho y Mutable
    SimboloImportantePocoPoco e Inmutable
    ValorTransparenteMuchoMucho e Inmutable
    Servicio-MuchoPoco
    DTOImportantePocoMucho y Mutable
    + +

    Algunas combinaciones nos llevan a: Identidad importante, estado y comportamiento inexistentes: símbolos, candados. Identidad y estado importante: entidades Comportamiento importante, estado e identidad insignificantes: objeto función, stratey stateless,

    + +

    Comportamiento ...

    + +

    Semántica de referencia vs semántica de valor

    + +
      +
    • Su identidad no es importante
    • +
    • (Consecuencia de lo anterior) Su estado, si importante, es constante.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/estrategias-de-evaluacion.html b/wiki/articles/estrategias-de-evaluacion.html new file mode 100644 index 0000000000..8d1478741b --- /dev/null +++ b/wiki/articles/estrategias-de-evaluacion.html @@ -0,0 +1,1242 @@ + + + + + + + + + + + Estrategias de evaluacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Estrategias de evaluacion +

    +
    + + + +
    +

    Estrategias de evaluación

    + +

    Introducción

    + +

    La operación que realizamos en funcional es aplicar funciones, la idea del tema que vamos a tratar a continuación es saber qué se tiene que tener en cuenta para determinar el orden en en que aplicarán las funciones de una expresión.

    + +

    Primer ejemplo

    + +
    +    masUno x = x + 1
    +
    +
    + +

    La expresión masUno (2*3) puede ser evaluada de la siguiente forma

    + +
    +    masUno (2*3)
    +
    +
    + +
      +
    • aplicamos *
    • +
    + +
    +    masUno 6
    +
    +
    + +
      +
    • aplicamos masUno
    • +
    + +
    +    6 + 1
    +
    +
    + +
      +
    • aplicamos +
    • +
    + +
    +    7
    +
    +
    + +

    Alternativamente podemos evaluar la misma expresión pero aplicando las funciones en el orden inverso

    + +
    +    masUno (2*3)
    +
    +
    + +
      +
    • aplicamos masUno
    • +
    + +
    +    (2*3) + 1
    +
    +
    + +
      +
    • aplicamos *
    • +
    + +
    +    6 + 1
    +
    +
    + +
      +
    • aplicamos +
    • +
    + +
    +    7
    +
    +
    + +

    No importa el orden en que apliquemos las funciones vamos a llegar al mismo resultado final. Esto no solo vale para ejemplos sencillos sino que se cumple siempre en Haskell.

    + +

    Esta propiedad no se cumple en la mayoría de los “lenguajes imperativos” (Pascal, C, Smalltalk, Java, C#, etc.), veamos un ejemplo en Smalltalk:

    + +

    Si tenemos la expresión n + (n := 1) y n empieza apuntando a 0.

    + +

    Si empezamos a evaluar de izquierda a derecha

    + +
    +   n + (n := 1)
    +
    +
    + +
      +
    • aplicamos n
    • +
    + +
    +   0 + (n := 1)
    +
    +
    + +
      +
    • aplicamos :=
    • +
    + +
    +   0 + 1
    +
    +
    + +
      +
    • aplicamos +
    • +
    + +
    +   1
    +
    +
    + +

    Si empezamos a evaluar de derecha a izquierda

    + +
    +   n + (n:= 1)
    +
    +
    + +
      +
    • aplicamos :=
    • +
    + +
    +   n + 1
    +
    +
    + +
      +
    • aplicamos n
    • +
    + +
    +   1 + 1
    +
    +
    + +
      +
    • aplicamos +
    • +
    + +
    +   2
    +
    +
    + +

    Como se puede observar, si evaluamos las expresiones con distintas estrategias obtenemos resultados distintos; esto sucede porque las operaciones involucradas no tienen transparencia referencial en este caso particular debido a la introducción de una asignación destructiva.

    + +

    Estrategias básicas

    + +

    A una expresión que consta de una función aplicada a uno o más parámetros y que puede ser “reducida” aplicando dicha función la vamos a llamar Redex (Reducible Expression). Se le dice reducción al hecho de aplicar la función no necesariamente vamos a obtener una expresión “más corta” como veremos más adelante. Consideremos la función mult que tiene como dominio una tupla de 2 números

    + +
    +   mult (x,y) = x * y
    +
    +
    + +

    Si queremos reducir la expresión mult (1+2,2+3) está expresión contiene 3 redexs

    + +
      +
    • +
        +
      1. 1+2 (la función + aplicada a 2 parámetros)
      2. +
      +
    • +
    • +
        +
      1. 2+3 (la función + aplicada a 2 parámetros)
      2. +
      +
    • +
    • +
        +
      1. mult (1+2,2+3) (la función mult aplicada a 1 parámetro que es una tupla)
      2. +
      +
    • +
    + +

    Si queremos evaluar la expresión ¿qué estrategia usamos?

    + +

    De adentro hacia afuera

    + +

    También conocida como call-by-value

    + +

    Una de las estrategias más comunes es comenzar desde adentro hacia afuera (innermost evaluation), esta estrategia elige el redex que está “más adentro” entendiendo por esto al redex que no contiene otro redex. Si existe más de un redex que cumple dicha condición se elige el que está más a la izquierda. Vamos al ejemplo

    + +
    +   mult (1+2,2+3)
    +
    +
    + +
      +
    • aplicamos el primer +
    • +
    + +
    +   mult (3,2+3)
    +
    +
    + +
      +
    • aplicamos el +
    • +
    + +
    +   mult (3,5)
    +
    +
    + +
      +
    • aplicamos mult
    • +
    + +
    +   3 * 5
    +
    +
    + +
      +
    • aplicamos *
    • +
    + +
    +   15
    +
    +
    + +

    Esta estrategia me asegura que los parámetros de una función están completamente evaluados antes de que la función sea aplicada. Por eso se dice que los parámetros se pasan por valor.

    + +

    De afuera hacia adentro

    + +

    También conocida como call-by-name

    + +

    Otra de las estrategias más comunes es comenzar desde afuera hacia adentro (outtermost evaluation), esta estrategia elige el redex que está “más afuera” entendiendo por esto al redex que no esta contenido en otro redex. Si existe más de un redex que cumple dicha condición se elige el que está más a la izquierda. Vamos al ejemplo

    + +

    mult (1+2,2+3)

    + +
      +
    • aplicamos mult
    • +
    + +
    +   (1+2) * (2+3)
    +
    +
    + +
      +
    • aplicamos el primer + (Si seguimos lo que dijimos arriba deberíamos aplicar primero el * pero vamos a explicar porque no lo hacemos más abajo)
    • +
    + +
    +    3 * (2+3)
    +
    +
    + +
      +
    • aplicamos +
    • +
    + +
    +    3 * 5
    +
    +
    + +
      +
    • aplicamos *
    • +
    + +
    +    15
    +
    +
    + +

    Usando esta estrategia las funciones se aplican antes que los parámetros sean evaluados. Por esto se dice que los parámetros se pasan por nombre. Nota: Hay que tener en cuenta que muchas funciones que ya vienen con Haskell requieren que sus parámetros estén evaluados antes de que la función sea aplicada, incluso cuando usamos la estrategia “de afuera hacia adentro”. Por ejemplo, el operador * y el + no pueden ser aplicados hasta que sus dos parámetros hayan sido evaluados a números. A las funciones que cumplen con esta propiedad las vamos a llamar funciones estrictas. Funciones estrictas que nos van a interesar a nosotros:

    + +
      +
    • Operaciones aritméticas (+,*,/,etc.)
    • +
    • Pattern-Matching (sobre listas, tuplas, etc.)
    • +
    + +

    Evaluaciones que no terminan

    + +

    Tengan en cuenta la siguiente definición

    + +
    +   inf = 1 + inf
    +
    +
    + +

    Intentar reducir la expresión inf siempre nos va a dar como resultado una expresión más y más grande (independientemente de la estrategia de evaluación que usemos)

    + +
    +   inf
    +
    +
    + +
      +
    • aplicamos inf
    • +
    + +
    +   1 + inf
    +
    +
    + +
      +
    • aplicamos inf (porque + es estricta)
    • +
    + +
    +   1 + (1 + inf)
    +
    +
    + +
      +
    • aplicamos inf (porque + es estricta)
    • +
    + +

    ….

    + +
    +   1 + (1 + (1 + (1 + (1 + (1 + .... + inf )))))
    +
    +
    + +

    Por ende, está evaluación nunca terminaría.

    + +

    Sabiendo que

    + +
    +   fst (x,_) = x
    +
    +
    + +

    Consideremos la expresión fst (0,inf)

    + +

    Usando la estrategia call-by-value

    + +
    +   fst (0,inf)
    +
    +
    + +
      +
    • aplicamos inf
    • +
    + +
    +   fst (0, 1 + inf )
    +
    +
    + +
      +
    • aplicamos inf
    • +
    + +
    +   fst (0, 1 + (1 + inf) )
    +
    +
    + +
      +
    • aplicamos inf
    • +
    + +
    +   fst (0, 1 + (1 + (1 + inf) ) )
    +
    +
    + +
      +
    • aplicamos inf
    • +
    + +

    + +

    Usando call-by-value la evaluación de la expresión no termina.

    + +

    Usemos call-by-name:

    + +
    +   fst (0,inf)
    +
    +
    + +
      +
    • aplicamos fst
    • +
    + +
    +   0
    +
    +
    + +

    Usando call-by-name la expresión se evalúa por completo con solo una reducción. En este ejemplo se puede ver que ciertas expresiones que pueden no terminar cuando se evalúan con la estrategia call-by-value pueden terminar cuando se usa la estrategia call-by-name.

    + +

    De forma más general: Si existe alguna secuencia de evaluación que haga terminar la evaluación de la expresión entonces con la estrategia call-by-name también se termina la evaluación y se produce el mismo resultado final.

    + +

    Corolario: si te es mucho muy importante que una expresión termine la estrategia que querés usar es call-by-name

    + +

    Lazy Evaluation

    + +

    Visión técnica

    + +

    Si tenemos la siguiente definición

    + +
    +   alCuadrado x = x * x
    +
    +
    + +

    Vamos a evaluar la expresión alCuadrado (2*3) usando call-by-value

    + +
    +   alCuadrado (1+2)
    +
    +
    + +
      +
    • aplicamos +
    • +
    + +
    +   alCuadrado 3
    +
    +
    + +
      +
    • aplicamos alCuadrado
    • +
    + +
    +   3 * 3
    +
    +
    + +
      +
    • aplicamos *
    • +
    + +
    +   9
    +
    +
    + +

    Ahora vamos a evaluar la misma expresión usando call-by-name

    + +
    +   alCuadrado (1+2)
    +
    +
    + +
      +
    • aplicamos alCuadrado el primer +
    • +
    + +
    +   (1+2) * (1+2)
    +
    +
    + +
      +
    • aplicamos el +
    • +
    + +
    +   3 * (1+2)
    +
    +
    + +
      +
    • aplicamos el *
    • +
    + +
    +   3 * 3
    +
    +
    + +
      +
    • aplicamos el *
    • +
    + +
    +   9
    +
    +
    + +

    Llegamos la mismo resultado pero en el segundo ejemplo realizamos una reducción más (4 reducciones vs 3 reducciones).

    + +

    Con call-by-name la expresión (1+2) se evaluó dos veces.

    + +

    Corolario: cuando usamos call-by-value los parámetros son evaluados una y solo una vez; cuando usamos call-by-name el mismo parámetro puede llegar a ser evaluado más de una vez.

    + +

    Para evitar este quilombo en vez de tener la expresión (1+2) vamos a tener un “puntero a la expresión” llamémoslo p.

    + +
    +  alCuadrado (1+2)
    +
    +
    + +
      +
    • aplicamos alCuadrado
    • +
    + +
    +  let p = (1+2) in p * p
    +
    +
    + +
      +
    • aplicamos +
    • +
    + +
    +  let p = 3 in p * p
    +
    +
    + +
      +
    • aplicamos *
    • +
    + +
    +   9
    +
    +
    + +

    Cualquier reducción que se haga en una expresión se va a conocer automáticamente por los punteros a dicha expresión. Al uso de punteros para compartir expresiones que representan la mismo parámetro lo vamos a llamar Sharing. Al uso de la estrategia call-by-name más el Sharing lo vamos a llamar Lazy Evaluation (esta es la estrategia que usa Haskell). El Sharing nos asegura que usar Lazy Evaluation nunca requiera más pasos que la estrategia call-by-value.

    + +

    Visión operativa

    + +

    A efectos de resumir lo que vimos hasta ahora vamos a entender lo siguiente …

    + +

    Lazy Evaluation: con esta estrategia los parámetros solo se resuelven cuando son necesarios (y son evaluados solo lo necesario). También conocida como evaluación perezosa o diferida.

    + +

    A la estrategia call-by-value (y sus variantes) también se las conoce como Eager Evaluation. Eager Evaluation: con esta estrategia los parámetros tienen que resolverse antes de aplicar la función. También conocida como evaluación ansiosa.

    + +

    Estructuras infinitas

    + +

    Pensemos en la siguiente definición

    + +
    +    unos = 1 : unos
    +
    +
    + +

    (A partir de ahora vamos a pensar que evaluamos todo en Haskell así que la estrategia que usamos es Lazy Evaluation)

    + +
    +   unos
    +
    +
    + +
      +
    • aplicamos unos
    • +
    + +
    +   1 : unos
    +
    +
    + +
      +
    • aplicamos unos
    • +
    + +
    +   1 : ( 1 : unos )
    +
    +
    + +
      +
    • aplicamos unos
    • +
    + +

    + +

    En Haskell

    + +
    +    > unos
    +   [1,1,1,1,1,1,1........
    +
    +
    + +

    Como se puede ver la evaluación de unos no termina. A pesar de esto podemos usar la expresión unos dentro de nuestro programa y aplicarla a otras funciones. Por ejemplo

    + +

    Siendo head (x:_) = x y la expresión head unos

    + +
    +   head unos
    +
    +
    + +
      +
    • deberíamos aplicar head pero como head me fuerza a tener la lista separada en cabeza:cola tenemos que evaluar unos por el pattern-matching
    • +
    + +
    +   head (1:unos)
    +
    +
    + +
      +
    • aplicamos head
    • +
    + +
    +   1
    +
    +
    + +

    Con este ejemplo podemos ver que unos no es una lista infinita sino potencialmente infinita, si aplicamos sobre ella funciones que no la fuerzan a evaluarse por completo la computación termina (eso sonó apocalíptico). La potencia de Lazy Evaluation está en que la expresión unos se evalúa solo lo necesario para que pueda usarla la función que la recibe como parámetro.

    + +

    Listas infinitas

    + +

    Ya vimos la lista de unos que es “infinita”, ahora veamos como hacer una lista que tenga todos los números naturales

    + +
    +   naturalesDesde x = x : naturalesDesde (x+1)
    +
    +
    + +
    +   > naturalesDesde 1
    +   [1,2,3,4,5,6,7,8,9,...........
    +
    +
    + +

    Haskell trae un atajo para esto

    + +
    +   naturalesDesde x = [x..]
    +
    +
    + +

    También sirve para hacer listas con alguna condición entre dos de sus elementos consecutivos

    + +
    +   > [1,3..]
    +   [1,3,5,7,9,11,.........
    +
    +
    + +

    Entonces si queremos obtener los primeros 24 múltiplos de 13 podemos hacerlo de esta forma:

    + +
    +   > [13,26..24*13]
    +   [13,26,39,52,65,78,91,104,117,130,143,156,169,182,195,208,221,234,247]
    +
    +
    + +

    Pero también podemos resolverlo con una lista infinita usando take como veremos a continuación gracias a la evaluación perezosa.

    + +
    +   > take 24 [13,26..]
    +   [13,26,39,52,65,78,91,104,117,130,143,156,169,182,195,208,221,234,247]
    +
    +
    + +

    Ejemplos

    + +

    Dada la siguiente definición de take

    + +
    +   take 0 _ = []
    + take _ [] = []
    + take n (x:xs) = x : (take (n-1) xs)
    +
    +
    + +
    +   take 3 [1..]
    +
    +
    + +
      +
    • aplicamos ..
    • +
    + +
    +   take 3 (1:[2..])
    +
    +
    + +
      +
    • aplicamos take - 3ra línea
    • +
    + +
    +   1 : (take 2 [2..])
    +
    +
    + +
      +
    • aplicamos ..
    • +
    + +
    +   1 : (take 2 (2:[3..]))
    +
    +
    + +
      +
    • aplicamos take - 3ra línea
    • +
    + +
    +   1 : ( 2 : (take 1 [3..]))
    +
    +
    + +
      +
    • aplicamos ..
    • +
    + +
    +   1 : ( 2 : (take 1 (3:[4..])))
    +
    +
    + +
      +
    • aplicamos take - 3ra línea
    • +
    + +
    +   1 : ( 2 : ( 3 : (take 0 [ 4.. ]))))
    +
    +
    + +
      +
    • aplicamos take - 1ra línea
    • +
    + +
    +   1 : ( 2 : ( 3 : [] ))) = [1,2,3]
    +
    +
    + +

    Vamos a otro ejemplo

    + +
    +   take 3 [4+5,2/0,3*2]
    +
    +
    + +
      +
    • aplicamos el + (porque dice x: en take 3ra línea)
    • +
    + +
    +   take 3 [9,2/0,3*2]
    +
    +
    + +
      +
    • aplicamos take - 3ra línea
    • +
    + +
    +   9 : take 2 [2/0,3*2]
    +
    +
    + +
      +
    • aplicamos /
    • +
    + +
    +   9 : ERROR DIVISON BY ZERO !!!
    +
    +
    + +

    Dada la definición de (!!)

    + +
    +  (!!) 0 (x:_) = x
    +(!!) n (_:xs) = (!!) (n-1) xs
    +
    +
    + +
    +  (!!) 2 [4+5,2/0,3*2]
    +
    +
    + +
      +
    • aplicamos el !! (no es necesario aplicar el + porque en (!!) dice (_:xs) )
    • +
    + +
    +  (!!) 1 [2/0,3*2]
    +
    +
    + +
      +
    • aplicamos el !! (no es necesario aplicar la / por lo anterior)
    • +
    + +
    +  (!!) 0 [3*2]
    +
    +
    + +
      +
    • aplicamos * (porque la primer línea de !! lo pide)
    • +
    + +
    +  (!!) 0 [6]
    +
    +
    + +
      +
    • aplicamos !!
    • +
    + +
    +  6
    +
    +
    + +

    Supongamos que hacemos esta consulta:

    + +
    +   > head (filter (3<) [1..])
    +
    +
    + +

    Si bien la expresión filter (3<) [1..] no termina (seguiría buscando cuáles son mayores a 3 infinitamente), como lo que primero se evalúa es el head y se difiere la ejecución del filtrado, la ejecución va a terminar en cuanto el filter encuentre su primer elemento que pertenezca a la solución que es el 4.

    + +

    Es importante notar que en este otro caso:

    + +
    +   > head (filter (<0) [1..])
    +
    +
    + +

    La evaluación nunca termina por más que se use head que era lo que antes acotaba la ejecución, ya que nunca se va a encontrar el primer elemento que cumpla la condición a diferencia del caso anterior.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/evaluacion-diferida-y-diseno.html b/wiki/articles/evaluacion-diferida-y-diseno.html new file mode 100644 index 0000000000..0b8716e835 --- /dev/null +++ b/wiki/articles/evaluacion-diferida-y-diseno.html @@ -0,0 +1,306 @@ + + + + + + + + + + + Evaluacion diferida y diseno + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Evaluacion diferida y diseno +

    +
    + + + +
    +
      +
    • Como impacta al momento de hacer debug
    • +
    • Como su aplicabildiad está limitada por los efectos
    • +
    • Como simplifica el código (ejemplo con hibernate?)
    • +
    • como puede impactar negativamente o positvamente en el rendimiento
    • +
    • Como se relaciona con LazyObject y FunctionObject
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/excepciones-avanzadas.html b/wiki/articles/excepciones-avanzadas.html new file mode 100644 index 0000000000..2596c7975b --- /dev/null +++ b/wiki/articles/excepciones-avanzadas.html @@ -0,0 +1,440 @@ + + + + + + + + + + + Excepciones - Resumen avanzado + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Excepciones - Resumen avanzado +

    +
    + + + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Material

    + +

    Pueden ver un apunte completo en este link

    + +

    Formas de manejar una excepción

    + +

    Propagarla

    + +

    Es una buena opción cuando no se cómo salvar la situación, e implica

    + +
      +
    1. propagar la misma exception (declarando throws XXXException en la firma del método)
    2. +
    3. envolverla (wrappearla) en otra nueva, que agregará un mensaje de más alto nivel. Ej:
    4. +
    + +
    +
    +
    +      public void enviarResumenMensual(Cliente c) {
    +    try {
    +        String resumen = this.generador.crearResumen(c);
    +        this.clienteMail.enviarMail(c.getEmail(), resumen);
    +    } catch (EmailException e) {
    +        throw new ProgramException("Error al enviar el resumen por mail al usuario " + c.getNombre(), e);
    +    }
    +}
    +
    +    
    +
    +
    + +

    Tratarla

    + +

    Cuando tengo un requerimiento específico como:

    + +
      +
    • Si falla el servidor de mail, intentar con una lista de otros servidores alternativos.
    • +
    • Si falla el servidor de mail, esperar 5 segundos y reintentar. Realizar esto unas 5 veces. Caso que siga fallando, abortar el envío con un mensaje.
    • +
    + +

    Buenas Prácticas

    + +
      +
    • Nunca catchear una exception para no hacer nada. No hacer nada también incluye el “loggearla”. Es decir, catchear para loggear y seguir adelante, debería sonar muy raro. Tal vez tenga sentido eso como requerimiento en un único lugar de la arquitectura, para que no se caiga completamente la aplicación. Pero en el 99% de las veces es una hackeada.
    • +
    • En general wrappear para agregar información de contexto (qué estaba haciendo este método al encontrar un error en otro al que llama) +
        +
      • Así al momento de fallar una operación de negocio no terminamos con un solo mensaje puntual muy específico que será dificil de comprender para el usuario/administrador/programador, como “No me pude conectar al host 12.23.22.12”, si no una jerarquía de mensajes desde lo más general a lo más específico como:
      • +
      +
    • +
    + +
    +
    +
    +      Error al ejecutar el ciclo de facturación
    +  -> Error al facturarle al usuario numero 5963472
    +     -> Error al enviar el resumen mensual
    +        -> Error al enviar el mail
    +           -> No me pude conectar al host 12.23.22.12
    +
    +    
    +
    +
    + +

    No olvidar de pasar la causa original del error al wrappear (en nuestro ejemplo, la referencia a través de la variable e)

    + +
      +
    • Evitar try-catch dentro de otro try-catch: refactorizar la parte interna que puede fallar, llevándola a otro submétodo.
    • +
    • Evitar código antes y después de un try-catch, llevando todo el código a la forma
    • +
    + +
    +
    +
    +      método() {
    +    try {
    +        logica
    +    } catch
    +}
    +
    +    
    +
    +
    + +

    Es decir que el try-catch envuelva “todo” el código del método. Este va de la mano con la idea de hacer métodos más chiquitos. Al hacer una sola cosa, el método solo puede tener un tipo de falla.

    + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/excepciones.html b/wiki/articles/excepciones.html new file mode 100644 index 0000000000..35247c7c69 --- /dev/null +++ b/wiki/articles/excepciones.html @@ -0,0 +1,488 @@ + + + + + + + + + + + Excepciones + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Excepciones +

    +
    + + + +
    +

    Introducción

    + +

    Cuando un programa se ejecuta, pueden ocurrir errores: problemas de diversa índole que hacen que el sistema se comporte de una forma no esperada: el usuario ingresó un valor inválido, un objeto mal programado envió un mensaje con parámetros incorrectos, etc. Si el programa continuara ejecutándose ignorando esto, lo único que lograríamos sería que se produzcan más errores, cada vez más graves. Entonces, ¿qué hacer ante un error?

    + +

    Lo más seguro es fallar, es decir, abortar el flujo de ejecución para impedir que el resto del programa continúe ejecutándose como si no hubiera pasado nada. Una forma de lograr esto es mediante el lanzamiento de excepciones.

    + +

    En general cada método desarrollado debería seguir las siguientes pautas:

    + +
      +
    • Tener un nombre descriptivo, ya que dicho nombre nos dice qué esperar, es una promesa al usuario de lo que debería suceder luego de mandar el mensaje
    • +
    • Hacer todo y sólo lo que el nombre indica
    • +
    • Si por algún motivo no se puede cumplir con lo prometido por el nombre del método, explotar de la forma más prolija posible
    • +
    + +

    Es importante que aquellas cosas que puedan ser validadas para saber si no se podrá cumplir con lo prometido, se validen previamente a producir efectos colaterales, de esa forma podemos evitar algunas posibles inconsistencias en caso de poder seguir adelante manejando el problema de alguna forma.

    + +

    Excepciones

    + +

    Una excepción es la indicación de un problema que ocurre durante la ejecución de un programa. La principal particularidad de las excepciones es que cortan el flujo de ejecución hasta que alguien se encargue de resolverlo. Supongamos que tenemos este código Wollok:

    + +
    object prueba {
    +  method msj1(){
    +    self.msj3(self.msj2())
    +  }
    +  
    +  method msj2(){
    +    self.error("Todo mal!")
    +    return "Esto no se va a ejecutar nunca"
    +  }
    +  
    +  method msj3(string) = "Opa! " ++ string
    +}
    +
    + +

    De esta forma si el objeto que define esto recibe el mensaje msj1, la excepción lanzada en msj2 cortará la ejecución con lo cual no se evaluará la siguiente línea ni se mandará msj3. Es correcto dejar que la excepción se propague hacia atrás por la cadena de mensajes enviados siempre que no haya nada para hacer al respecto. Eventualmente, en algún punto donde sí sea posible tomar alguna acción, se podrá manejar esta excepción y continuar la ejecución con normalidad.

    + +

    Bugs vs Errores de usuario

    + +

    Algunos errores surgen por un bug en el programa, por ejemplo si un objeto no entiende un mensaje la forma de resolverlo es modificar el código para que o bien lo entienda o el mismo no le llegue dependiendo de si debería o no entenderlo. Por ejemplo, si a un Set le pedimos el primer elemento tira un error porque no es una colección ordenada, por ende no debe responder al mensaje first como sí lo hace una colección ordenada.

    + +

    Otros errores surgen del uso del programa, ya que pueden darse situaciones que llevan a que un objeto no pueda realizar lo que se le pide. Por ejemplo, si a una colección vacía el mandamos el mensaje anyOne tira un error porque no tiene forma de resolver el problema.

    + +

    Lanzando Excepciones

    + +

    En Wollok la forma más fácil de lanzar una excepción es mediante un mensaje a self (en este caso error(descripcion)) que todos los objetos entienden. Por ejemplo:

    + +
    object pepita {
    +  var energia = 100
    +  method vola(unosKms){
    +    if(energia < unosKms){
    +      self.error("Energía insuficiente para volar los kilómetros requeridos")
    +    }
    +    energia = energia - unosKms
    +  }
    +}
    +
    + +

    En el ejemplo vemos que si la energía de pepita es menor a la cantidad de kilómetros pasados por parámetro, la operación no debería realizarse porque quedaría con energía negativa. Para evitar que eso pase se lanza el error con una descripción simpática para que el usuario o el desarrollador (dependiendo de si debería o no llegarse a esa situación) entienda qué fue lo que pasó. Lo interesante es que la línea que modifica la energía sólo llega a ejecutarse si energia >= unosKms.

    + +

    Otra forma de lanzar excepciones es usando clases pertenecientes a una jerarquía particular, que son de tipo excepción. El ejemplo anterior podría reescribirse de la siguiente forma, usando DomainException que es el mismo tipo de excepción que usa el mensaje error por atrás y hereda de la clase Exception:

    + +
    object pepita {
    +  var energia = 100
    +  method vola(unosKms){
    +    if(energia < unosKms){
    +      throw new DomainException(message = "Energía insuficiente para volar los kilómetros requeridos")  // se usa la palabra reservada throw con la excepción a lanzar
    +    }
    +    energia = energia - unosKms
    +  }
    +  ...
    +}
    +
    + +

    Esto así como está no tiene ninguna ventaja sobre lo anterior, que era bastante más bonito y simple. Para que tenga sentido, tenemos que pensar en este problema en un contexto más amplio…

    + +

    ¿Cómo evitar que se rompa todo ante situaciones excepcionales?

    + +

    Algunos errores pueden evitarse realizando validaciones previas, pero no siempre es posible o deseable usar este enfoque. Entonces, una vez que se produce el error tenemos que tener una forma de recuperarnos del mismo para que el programa no termine con excepción.

    + +

    Lo que deberíamos hacer en aquellos lugares en donde sabemos qué hacer ante un problema (que idealmente son muy pocos) es atrapar la excepción que causó el problema y evaluar un determinado código para seguir adelante de forma correcta. Para eso primero tenemos que saber qué parte del código a ejecutar es el que podría terminar en excepción, luego qué tipo de error queremos tratar y finalmente qué se debería hacer al respecto.

    + +

    El siguiente código va a pedirle a pepita que vuele, que puede romperse y supongamos que la forma de reaccionar ante alguna excepción según el requerimiento sea darle de comer para que no se muera:

    + +
    try {
    +  pepita.vola(100)
    +} catch e : Exception {
    +  pepita.come(50)
    +}
    +
    + +

    Un problema que tiene esta solución es que para cualquier problema se le va a dar de comer a pepita, si la energía de pepita no estuviera inicializada y el error surge de intentar tratar a la nada como un número, o si pepita no entiende el mensaje para volar, también resolvería el problema con el bloque que le da de comer en vez de romperse, de modo que sepamos que el problema existe. Eso lógicamente no es correcto.

    + +

    Considerando que el mensaje self.error(descripcion) lanza una excepción más particular que Exception, una primer mejora que se puede hacer es acotar ante qué tipo de error queremos darle de comer a pepita:

    + +
    try {
    +  pepita.vola(100)
    +} catch e : DomainException {
    +  pepita.come(50)
    +}
    +
    + +

    Eso va a evitar que nos recuperemos incorrectamente de errores como ser mensajes no entendidos, ya que no son de tipo DomainException, sin embargo sería interesante poder refinarlo un poco más, para tener la certeza de que sólo vamos a estar manejando con este mecanismo las excepciones que surjan por tener energía insuficiente.

    + +

    Acá entra en juego nuevamente la jerarquía de clases de excepción. En vez de simplemente usar self.error(descripcion), podríamos tener clases propias que hereden de la clase de excepción más apropiada (en este caso DomainException podría tener sentido):

    + +
    class EnergiaInsuficienteException inherits DomainException {}
    +
    + +

    …y luego hacer algo así en el método vola(kms) de pepita: throw new EnergiaInsuficienteException(message = "Energía insuficiente para volar los kilómetros requeridos").

    + +

    Eso permite atrapar sólo las excepciones que me interesan y dejar pasar las que no sé cómo manejar para que alguien más se ocupe. Por ejemplo:

    + +
    try {
    +  pepita.vola(100)
    +} catch e:EnergiaInsuficienteException {
    +  pepita.come(50)
    +}
    +
    + +

    También, si estamos testeando podemos verificar que el resultado de ejecutar algo sea no poder volar:

    + +
    assert.throwsExceptionWithType(new EnergiaInsuficienteException(), {pepita.vola(100)})
    +
    + +

    Al usar throwsExceptionWithType el test va a dar verde exclusivamente cuando el bloque al ejecutarse lanza una excepcion cuya clase sea EnergiaInsuficienteException o alguna subclase de la misma. Si el error que lanza ejecutar ese bloque es por ejemplo que un objeto no entendió un mensaje como se explicó antes, el test no va a dar verde, y es exactamente lo que necesitamos.

    + +

    Estrategias para manejar excepciones

    + +
      +
    • La forma por excelencia de lidiar con una excepción es no hacer nada!!. La mayoría de las veces no tenemos la capacidad de recuperarnos del problema en el mismo lugar donde se produce, lo más sano es dejarla burbujear hasta el punto en donde sí haya algo para hacer al respecto.
    • +
    • Atraparla, hacer algo y continuar con el flujo normal de ejecución.
    • +
    • Atraparla, hacer algo y volver a lanzar la misma excepción. Eso se puede hacer volviendo a usar throw usando la excepcion atrapada en el bloque que maneja el problema.
    • +
    • Atraparla y lanzar otra más adecuada agregando más información del problema. Las excepciones además de un mensaje descriptivo pueden tener asociada una causa que es otra excepción y sirve justamente para los casos en los cuales se usa esta estrategia. Si vemos stacktrace completo de una excepción que tiene una instancia de otra excepción como causa, podremos notar que se incluye la información de ambas excepciones, sin perder información por el camino.
    • +
    + +

    ¿Donde es común atrapar excepciones?

    + +

    Lo más usual es que las excepciones no se atrapen en el código de nuestros objetos de dominio, sino mucho más lejos, en unos pocos lugares puntuales. Por ejemplo, si tenemos un sistema con una interfaz gráfica que es la que el usuario final usa para interactual, vamos a querer que en esa interfaz se muestre un mensaje razonable para que el usuario vea. Por ejemplo, si el problema está relacionado con alguna acción incorrecta por parte del usuario, lo ideal sería comunicársela de modo que pueda entender el problema y corregirlo; si en cambio es un problema inesperado sobre el cual el usuario no puede hacer nada (un problema del programa en sí, no del uso), se le podría mostrar otro tipo de mensaje para que sepa que hubo un problema y también informar del problema a los desarrolladores para que puedan analizarlo y trabajar sobre la causa.

    + +

    En las herramientas de testeo que usan nuestro código también de seguro se están atrapando las excepciones que se lancen al ejecutar nuestra lógica, lo cual lleva a que se reporte adecuadamente si las pruebas pasaron, si falló una aserción o si hubo un error inesperado, y la información de esas excepciones que se atraparon debería poder ser vista por quien corre las pruebas.

    + +

    Eso no quiere decir que nunca se atrapen excepciones dentro del modelo, sin embargo hay que entender que no es tan común, y es importante no abusar de estas herramientas, ya que podrían traer más problemas que soluciones.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/expresiones-lambda.html b/wiki/articles/expresiones-lambda.html new file mode 100644 index 0000000000..18f0571630 --- /dev/null +++ b/wiki/articles/expresiones-lambda.html @@ -0,0 +1,398 @@ + + + + + + + + + + + Expresiones lambda + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Expresiones lambda +

    +
    + + + +
    +

    Son funciones anónimas. Por ej., una función anónima que toma solo un número como argumento y produce el resultado x + x se puede definir como:

    + +

       λx → x + x

    + +

    En Haskell:

    + +

    λ se escribe \ y se escribe ->;

    + +

    Esa definición no es más que una función doble, por eso podemos escribir

    + +
    doble = \x -> x + x
    +
    + +

    A pesar de no tener nombre, pueden usarse como cualquier otra función:

    + +
    >(\x -> x + x) 2
    +4
    +
    + +

    Una expresión lambda puede recibir más de 1 parámetro separándolos por espacio dentro de la expresión

    + +
    --cuentaLoca es una función que recibe 3 parámetros
    +cuentaLoca = (\x y z -> x * 2 - y + 10 * z)
    +
    + +

    La gracia de poder definir funciones anónimas es que nos permite armar fácilmente una función para usar en el momento. En general cuando más jugo se les saca a las expresiones lambda es para usar funciones de orden superior, sin embargo pueden usarse en cualquier lugar donde se espere una función. Como las expresiones lambda son funciones, las mismas pueden combinarse con otras funciones usando Composición.

    + +

    Una de las ventajas que tienen las lambdas por sobre otros mecanismos de crear nuevas funciones cuando las necesito sin tener que definirlas en otro lado, es que los parámetros tienen un nombre y puedo usar ese mismo parámetro tantas veces como quiera dentro de la definición. Si por ejemplo quisiéramos saber si la edad de una persona es menor a 20 o mayor a 60, podría resolverse de la siguiente forma:

    + +
    > ((\e -> e < 20 || e > 60).edad) persona
    +
    + +

    Algo importante a tener en cuenta es que si no le damos un nombre a nuestras funciones podríamos perder abstracciones útiles que podrían luego ser utilizadas en otros puntos de nuestro programa, por lo tanto es importante ser criteriosos respecto a si es una buena idea buscar un nombre para nuestra función.

    + +

    Por lo general, si tengo una forma sencilla de nombrar una determinada lógica que forma parte de una función más grande, lo más probable es que no quiera definir ese pedacito de lógica usando una lambda, sino con una función que se llame como la idea que tenemos en la cabeza. Si no hay un nombre claro asociado a ese pedacito de lógica, lo más probable es que no sea un concepto del dominio que merezca la pena modelar como algo aparte.

    + +

    Lambdas y Pattern Matching

    + +

    Algo interesante que se puede hacer con las expresiones lambda es descomponer sus parámetros usando pattern matching como cuando definimos funciones normales. Supongamos que dado un alumno modelado con una tupla de tipo (String, [Int]) quiero obtener la primer nota que se sacó, se podría resolver de la siguiente forma:

    + +
     > (\(_,(nota:_)) -> nota) alumno
    +
    + +

    Al usar pattern matching hay que tener en cuenta que si el parámetro que le llega a la lambda no matchea (por ejemplo si en este caso el alumno no tiene notas), al ejecutarse va a tirar un error indicando que los patrones usados no fueron exhaustivos, lo que significa que la función tiene un dominio acotado, posiblemente más de lo que queríamos.

    + +

    Para este ejemplo no nos interesa contemplar a los alumnos sin notas porque no tenemos una buena respuesta para dar en ese escenario, con lo cual la solución sería correcta.

    + +

    Uso de lambdas en vez de aplicación parcial

    + +

    Uno de los conceptos fuertes que existen en el paradigma funcional es el de Aplicación Parcial, que nos permite crear una función nueva a partir de otra existente cuando nos hace falta para combinarla con otras funciones mediante composición o simplemente pasarla por parámetro para que otra función la evalúe cuando corresponda.

    + +

    Siempre que usamos aplicación parcial podemos también usar una lambda, por ejemplo:

    + +
    > map (+1) [1 .. 10]
    +
    + +

    Tiene el mismo resultado que:

    + +
    > map (\n -> n + 1) [1 .. 10]
    +
    + +

    En casos como este, el uso de aplicación parcial es más interesante que el uso de la expresión lambda. No sólo hacemos lo mismo con menos código sino que demostramos un mayor entendimiento de los conceptos más fuertes del paradigma.

    + +

    Sin embargo hay casos en los cuales no podemos resolver el problema aplicando parcialmente (ver: Puedo aplicar parcialmente el segundo parámetro en vez del primero?) la función que queremos usar que sí justifican el uso de una expresión lambda.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/expresividad.html b/wiki/articles/expresividad.html new file mode 100644 index 0000000000..f7087829fa --- /dev/null +++ b/wiki/articles/expresividad.html @@ -0,0 +1,432 @@ + + + + + + + + + + + Expresividad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Expresividad +

    +
    + + + +
    +

    Definición

    + +

    La expresividad puede definirse informalmente con la heurística “el nivel de lindez del código”. En otras palabras, escribir un código expresivo es poner atención a las cuestiones que hacen que este código fuente sea más fácil de entender por una persona.

    + +

    ¿Por qué por una persona y no por una pc?

    + +

    Para responder esa pregunta comparemos estos dos códigos en Pascal:

    + +
    Function QuieroMoverElBote(a: Array of Integer, c:Integer):Real;
    +Var b  : Integer; d  : Real; e  : Integer; 
    +Begin
    + For b := 1 to c do 
    +  Begin 
    +   e := e + a[b];
    +  End;  
    + d := e / c;
    + QuieroMoverElBote := d; 
    +End.
    +
    +Function Promedio(numeros: Array of Integer, cantidad:Integer):Real;
    +Var i  : Integer; sumatoria  : Integer;
    +Begin
    + For i := 1 to cantidad do
    +  Begin
    +   sumatoria := sumatoria + numeros[i];
    +  End;
    + Promedio := sumatoria / cantidad;
    +End.
    +
    + +

    En la segunda implementación puede verse con claridad el objetivo de este programa, mientras que en el primero está “escondido”. Sin embargo, la computadora ejecutando este código produce exactamente el mismo resultado con cualquiera de los dos programas. La diferencia está en el programador que lee un programa ó el otro.

    + +

    Es por eso que muchas veces se suele considerar a la Expresividad como algo subjetivo. Sin embargo, en líneas generales, hay formas de alcanzar la expresividad.

    + +

    Motivación

    + +

    En general, las técnicas que favorecen la mejor comprensión del código fuente (por un programador) son técnicas que no cambian en funcionamiento del programa. Entonces, si en última instancia el programa hace lo que corresponde, ¿Por qué habríamos de consumir tiempo escribiendo código expresivo?

    + +

    En la industria actual de software (de hecho, en cualquier ambiente en el que sea necesaria la producción de software) existen ciertas características / problemas a resolver, consecuencia de que los programas son cada vez más grandes, complejos, y cambiantes. En consecuencia:

    + +
      +
    • Se espera que sean flexibles (que puedan cambiarse fácilmente)
    • +
    • Se espera que “fallen poco” (con lo cual es importantísimo encontrar y corregir errores tempranamente).
    • +
    • El desarrollo dura mucho tiempo. (Meses, años)
    • +
    • El equipo de desarrollo es amplio. (Mucha gente escribiendo el mismo programa).
    • +
    + +

    En consecuencia, la labor de un programador es en su amplia mayoría, leer y corregir código existente (propio ó de otro) y en menor medida producir código nuevo.

    + +

    Es por todo esto que el código fuente no puede ser exclusivamente escrito para la computadora. El más importante destino del código son las propias personas. Es por eso que no se puede descuidar la expresividad: es una de las varias formas de hacer la vida del programador más sencilla, para que pueda abordar la construcción de sistemas como el mencionado.

    + +

    Cómo lograr la expresividad

    + +

    Hay varias formas de lograr expresividad, entre las que se destacan:

    + +
      +
    • Usar buenos nombres
    • +
    • Usar buenas abstracciones en general (y en particular, la Declaratividad).
    • +
    • Identar correctamente el código.
    • +
    + +

    Buenos Nombres

    + +

    Buen resumen (en inglés) http://c2.com/cgi/wiki?GoodVariableNames

    + +
      +
    • Un buen nombre debe decir exactamente cuál es el propósito de la variable / procedimiento / método. +
        +
      • Por ejemplo, la función de arriba pasó de llamarse QuieroMoverElBote a Promedio, y el array de llamarse a a llamarse numeros.
      • +
      +
    • +
    • Ser descriptivo. +
        +
      • Por ejemplo, no tener miedo de escribir nombres largos. cantAlumnosAprobados es mejor que aprobados.
      • +
      +
    • +
    • Ser claro y simple. +
        +
      • Por ejemplo, se pueden usar abreviaciones claras (como cant en vez de cantidad). Aunque las abreviaciones pueden resultar a veces dañinas: alumnosAprobados es mejor que alsAp
      • +
      +
    • +
    • Respetar las convenciones es buena idea. +
        +
      • Por ejemplo, el código escrito en lenguaje Python separa las palabras dentro de un nombre así: esto_es_una_variable, mientras que en Smalltalk la convención es así: estoEsUnaVariable.
      • +
      +
    • +
    • Dar idea (no muy específica) del tipo ayuda también a la expresividad. +
        +
      • Por ejemplo, en el array del ejemplo de arriba hay una variable que se llama numeros. Esto da a entender rápidamente que son muchos, y que son de algún tipo numérico, exactamente cuál no es importante para entender qué hace. Ejemplos de malos nombres son numero, ints ó arrayNumeros. Tampoco es buena idea llamar a la función realPromedio, porque ensucia la legibilidad. Se sobreentiende que un promedio es de un tipo real ó flotante.
      • +
      +
    • +
    + +

    El tiempo que uno gasta en encontrar/pensar un buen nombre, es tiempo bien aprovechado.

    + +

    Declaratividad

    + + + +

    Identación

    + +

    Identar el código (separar con espacios) es una buena manera de hacer que el código sea legible. Nuevamente, no debe abusarse de ésto, ni usarlo poco. Y respetar las convenciones del lenguaje es buena idea. En el ejemplo de arriba se ve claramente cómo la identación ayuda a leer mejor el programa, y de paso se respeta la identación sugerida de Pascal.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/fideos.html b/wiki/articles/fideos.html new file mode 100644 index 0000000000..912f75d337 --- /dev/null +++ b/wiki/articles/fideos.html @@ -0,0 +1,305 @@ + + + + + + + + + + + Fideos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Fideos +

    +
    + + + +
    +

    Proporciones:

    + +
      +
    • 100gr harina
    • +
    • 1 huevo
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/flattening-vs-linearization.html b/wiki/articles/flattening-vs-linearization.html new file mode 100644 index 0000000000..6a0fd5a5e8 --- /dev/null +++ b/wiki/articles/flattening-vs-linearization.html @@ -0,0 +1,315 @@ + + + + + + + + + + + Flattening vs linearization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Flattening vs linearization +

    +
    + + + +
    +

    Cuando el comportamiento de un objeto es separado en distintas abstracciones, es necesario definir cómo se resolverá la tarea de encontrar el comportamiento definido (method lookup).

    + +

    Si las abstracciones son suficientemente dispares (sin comportamiento en común), pueden pensarse como complementarias, y, en consecuencia, la manera en la que se desarrolle dicha búsqueda no impactará en el comportamiento resultante. Sin embargo, cuando las abstracciones son análogas, o peor, contradictorias, el mecanismo que define el comportamiento final del objeto es un factor crítico.

    + +

    Todos los lenguajes que brindan dicha modularización de abstracciones ofrecen de una u otra manera un mecanismo de búsqueda de comportamiento, de donde se destacan dos visiones principales: linearización (o “linearization”) y el aplanado (“flattening”).

    + +

    La linearization es un mecanismo que define un orden para las abstracciones, priorizando unas sobre otras. A la hora de proveer un método, aquella con mayor prioridad es la que lo otorga. Todo mecanismo de linearization define un Method Resolution Order (MRO). El caso más común es el de la herencia simple, en donde si un objeto recibe un mensaje, el método que se ejecutará es el que esté más cercano avanzando hacia lo más general en la jerarquía de herencia. Este mecanismo también es usado para la herencia múltiple y los Mixins.

    + +

    El flattening es un mecanismo que no prioriza abstracciones, sino que deja al usuario resolver las situaciones contradictorias o “conflictos”, mediante diferentes herramientas. Los Traits de Smalltalk se manejan con flattening, y la manera de solucionar conflictos se basa en el uso de operaciones para ajustar la composición de traits a las necesidades de cada caso, siendo un mecanismo muy flexible y a la vez simple de entender. Respecto al method lookup, como este mecanismo aplana los métodos definidos en la clase usuaria, encontrar el método correspondiente a un mensaje provisto por la otra entidad es lo mismo que encontrar el método para un mensaje propio.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/fold.html b/wiki/articles/fold.html new file mode 100644 index 0000000000..2f6b271f91 --- /dev/null +++ b/wiki/articles/fold.html @@ -0,0 +1,431 @@ + + + + + + + + + + + Fold + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Fold +

    +
    + + + +
    +

    Existe una familia de funciones en Haskell para modelar un algoritmo que permite procesar una estructura de datos para construir un valor, a esta idea le decimos foldear (derivado del inglés, “to fold”) o reducir.

    + +

    ¿Cómo sumo los elementos de una lista? ¿Cómo multiplico los elementos de una lista? ¿Cómo concateno una lista de palabras?

    + +
    sum [] = 0 
    +sum (x:xs) = x + sum xs 
    +
    +prod [] = 1 
    +prod (x:xs) = x * prod xs 
    +
    +concatenar [] = [] 
    +concatenar (x:xs) = x ++ concatenar xs
    +
    + +

    O bien si usamos los operadores de forma infija…

    + +
    sum [] = 0 
    +sum (x:xs) = (+) x (sum xs) 
    +
    +prod [] = 1 
    +prod (x:xs) = (*) x (prod xs) 
    +
    +concatenar [] = []
    +concatenar (x:xs) = (++) x (concatenar xs)
    +
    + +

    Si vemos las diferencias entre estas funciones notamos que sólo cambia la operación a realizar y el valor inicial, por ende si queremos hacer una función que nos generalice el algoritmo tenemos que recibirlos como parámetro.

    + +

    En términos generales… ¿cómo la paso a una función de orden superior? Necesitamos:

    +
      +
    • una función que opera con dos parámetros
    • +
    • un valor inicial
    • +
    • una lista
    • +
    + +
    foldr :: (a -> b -> b) -> b -> [a] -> b 
    +
    + +

    Caso base: si la lista es vacía, devuelvo el valor inicial.

    + +
    foldr f valorInicial [] = valorInicial 
    +
    + +

    Si la lista no es vacía, ¿qué voy a tener que hacer? A partir de alguna de las funciones podemos trasladar:

    + +
    concatenar (x:xs) = (++) x (concatenar xs) 
    +foldr f valorInicial (x:xs) = f x (foldr f valorInicial xs)
    +
    + +

    Sumando con foldr

    + +
    sum = foldr (+) 0 
    +
    + +

    Para sumar una lista hay que aplicar la suma elemento por elemento arrancando de 0. Como es difícil de asimilar de golpe, vamos a hacer el seguimiento de un caso:

    + +
    > sum [2, 3, 5] 
    += foldr (+) [2, 3, 5] 
    += (+ 2) (foldr (+) 0 [3, 5]) 
    += (+ 2) ((+ 3) (foldr (+) 0 [5])) 
    += (+ 2) ((+ 3) ((+ 5) (foldr (+) 0 []))) 
    += (+ 2) ((+ 3) ((+ 5) 0)) <- caso base 
    += (+ 2) ((+ 3 5)) 
    += (+ 2) 8 
    += 10
    +
    + +

    Si revisan el Prelude, van a encontrar otra función similar:

    + +
    foldl f z [] = z 
    +foldl f z (x:xs) = foldl f (f z x) xs 
    +
    + +

    foldl vs foldr

    + +

    ¿Cuál es la diferencia? Revisemos los tipos:

    + +
    foldl :: (a -> b -> a) -> a -> [b] -> a
    +foldr :: (a -> b -> b) -> b -> [a] -> b 
    +
    + +

    Foldr trabaja asociando a derecha la función f, mientras que foldl trabaja asociando a izquierda la función f. El seguimiento de la sumatoria definida en base a foldl puede ayudar a entender cómo realiza la operatoria:

    + +
    sum = foldl (+) 0 
    +> sum [2, 3, 5] 
    += foldl (+) 0 [2, 3, 5] 
    += foldl (+) ((+) 0 2) [3, 5] 
    += foldl (+) ((+) 2 3) [5] 
    += foldl (+) ((+) 5 5) []
    += foldl (+) 10 [] 
    += 10 <- caso base
    +
    + +

    Y aquí vemos que el valor inicial del caso base es en realidad el resultado final. Para comparar la forma de trabajar de las dos funciones pueden realizar consultas de este estilo en su intérprete de Haskell (show es una función que retorna la representación de el valor recibido como string):

    + +
    > foldr (\x y -> concat ["(",x,"+",y,")"]) "0" (map show [1..13])
    +"(1+(2+(3+(4+(5+(6+(7+(8+(9+(10+(11+(12+(13+0)))))))))))))"
    +> foldl (\x y -> concat ["(",x,"+",y,")"]) "0" (map show [1..13])
    +"(((((((((((((0+1)+2)+3)+4)+5)+6)+7)+8)+9)+10)+11)+12)+13)"
    +
    + +

    Otras variantes de fold son foldl1 y foldr1 que trabajan de forma análoga a las anteriores sólo que toman como valor inicial al primer elemento de la lista. Eso es útil para los casos en los que la lista no debería estar vacía y/o no hay un valor adecuado para parametrizar. Veamos un ejemplo:

    + +
    maximum' = foldr1 max
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/formato-de-un-paper.html b/wiki/articles/formato-de-un-paper.html new file mode 100644 index 0000000000..1ccc015079 --- /dev/null +++ b/wiki/articles/formato-de-un-paper.html @@ -0,0 +1,397 @@ + + + + + + + + + + + Formato de un paper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Formato de un paper +

    +
    + + + +
    +

    No todas las secciones son necesarias, pueden haber otras secciones o con otros nombres. Este solo es un template de guía.

    + +

    Título

    + +

    Hay que elegir un buen título :)

    + +

    Abstract

    + +

    El abstract no es otra cosa que un resumen de todo el paper. Debería contener aproximadamente una oración para cada uno de los siguientes temas:

    + +
      +
    • contexto
    • +
    • problema
    • +
    • porque es un problema
    • +
    • solucion que se presenta
    • +
    • como lo que presentamos soluciona el problema
    • +
    • quizas algun ejemplo
    • +
    + +

    Después de leer el abstract, el lector debería saber de qué se trata el paper a groso modo, y poder decidir si quiere seguir leyéndolo o no, si le sirve o no…

    + +

    Introduction

    + +

    La introducción le muestra al lector que hicimos la tarea. Sí, que sabemos de qué estamos hablando, conocemos los problemas, conocemos lo que otra gente hizo. Aca se explica mucho del contexto en el que nos paramos y brevemente los otros puntos, ya que van a ser mejor explicados en las secciones que siguen.

    + +
      +
    • Context: contar el contexto del problema, qué tecnología, qué ambiente. ¿es relacionado a web apps? ¿A lenguajes con chequeo estático de tipos? ¿Lenguajes con herencia múltiple?
    • +
    • Problems: contar brevemente los problemas que se quieren solucionar
    • +
    • Current Solutions: contar brevemente las soluciones existentes que existen que atacan el problema
    • +
    • Contributions: que agregamos nosotros a la investigación en el tema
    • +
    • Outline: contar de qué se tratan las secciones que siguen. Es el típico “In section 2 we present… In section 3 we show our implementation of bleh”
    • +
    + +

    Problems

    + +
      +
    • Constraints: ¿Sobre qué limitaciones trabajamos? ¿Ambientes con mucha seguridad? ¿Sin conexión de red? ¿Vms restrictivas?
    • +
    + +

    Luego enumeramos los problemas actuales que vamos a encarar:

    + +
      +
    • Problem1
    • +
    • Problem2
    • +
    • Your solution in a nutshell: contamos nuestra solución muy brevemente, contando en muy pocas lineas qué problemas resolvemos. Estamos invitando a que nos sigan a la próxima sección.
    • +
    + +

    My Solution

    + +

    Contamos la solución. Hice X, Y y Z, que solucionan los problemas A, B y C, así y asá. No comparamos con otra gente ni otras soluciones. Esta sección es toda nuestra.

    + +

    Discussion

    + +

    La discusión es donde:

    + +
      +
    • nuestra solución se compara con las existentes
    • +
    • abrimos la puerta a líneas que no se llegaron a explorar aca, que podrían encararse en el futuro.
    • +
    + +

    Implementation

    + +

    Aca podemos hablar de nuestra implementación en particular. Es la parte menos de investigación(?).

    + +

    Evaluation

    + +

    Qué tan buena es nuestra implementación y como soluciona los problemas que enumeramos. Aca podemos poner benchmarks, métricas, etc.

    + + + +

    Aca normalmente se hablar de gente trabajando en cosas parecidas, no necesariamente sobre el mismo campo, o buscando la misma solución. Es bastante similar a Discussion, y por eso ambas secciones pueden ser una sola.

    + +

    Conclusion

    + +

    Es un resumen post lectura, o sea, el lector ya tiene nuestro laburo en la cabeza: “Nuestra solución X pareciera ser una buena solución al problema Y, aunque no tanto para el problema Z. Queda por explorar el camino J, que encaró inicialmente el autor Fulanito[cita]”

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/frases-teadepeanas.html b/wiki/articles/frases-teadepeanas.html new file mode 100644 index 0000000000..925e18f7ca --- /dev/null +++ b/wiki/articles/frases-teadepeanas.html @@ -0,0 +1,309 @@ + + + + + + + + + + + Frases teadepeanas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Frases teadepeanas +

    +
    + + + +
    +
    +

    The way to keep designers sharp and honest is to make them eat their own dog food. Michi Henning

    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/funciones-por-partes.html b/wiki/articles/funciones-por-partes.html new file mode 100644 index 0000000000..54127aa04b --- /dev/null +++ b/wiki/articles/funciones-por-partes.html @@ -0,0 +1,492 @@ + + + + + + + + + + + Funciones por partes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Funciones por partes +

    +
    + + + +
    +

    Concepto Matemático

    + +

    Las funciones partidas ó definidas por partes ó por trozos son funciones que para diferentes valores del dominio, tienen una definición diferente. Por ejemplo, si tenemos que definir la función Módulo, para ciertos valores del dominio la función será f(x) = x y para otros valores será f(x) = -x

    + +

    Notación Matemática

    + +

    + +

    Código en Haskell

    + +

    En Haskell, las funciones partidas se escriben con Guardas, y se escribe la imagen de cada parte a la derecha del igual:

    + +
    f x | x >= 0 = x
    +    | x <  0 = -x
    +
    + +

    Las funciones por partes no son la única forma de tener diferentes definiciones para una función, existen casos en los cuales alcanza con el uso de pattern matching.

    + +

    Errores Comunes

    + +

    No debemos confundir el uso de guardas (cuyo concepto se explicó arriba) con las funciones que devuelven booleanos.

    + +

    Ejemplo 1

    + +

    Tomemos éste ejemplo: “Cierta edad es adulta cuando es 18 ó más”

    + +
    esAdulta edad | edad >= 18 = True
    +              | otherwise = False
    +
    + +

    ¡Pero esto es un uso incorrecto de las guardas! En otras palabras: Si una expresión es verdadera ó falsa por sí sola, no se lo debo preguntar, tengo que devolver directamente eso.

    + +

    Ésta es la manera correcta de hacerlo:

    + +
    esAdulta edad = edad >= 18
    +
    + +

    Ejemplo 2

    + +

    Representemos una función que me diga si alguien siempre dice la verdad, sabiendo que “los niños y los borrachos siempre dicen la verdad” Ésta es una manera de hacerlo, errónea:

    + +
    siempreDiceLaVerdad alguien | esNiño alguien = True
    +                            | esBorracho alguien = True
    +                            | otherwise = False
    +
    + +

    Si bien ésto funciona, es un mal uso de las funciones por partes, ya que no es cierto que esa función tenga diferentes “partes”. La definición es lógica, y es una sola. Es un “ó” lógico:

    + +

    ¿Cuando alguien dice la verdad?

    + +
      +
    • cuando es niño
    • +
    • cuando es borracho
    • +
    + +

    Esa es la definición de la función. Recordemos que el ó logico se escribe así:

    + +
    Main> (1>34) || (even 4)
    +True
    +
    + +

    y el y lógico se escribe así:

    + +
    Main> (1>34) && (even 4)
    +False
    +
    + +

    Entonces, mi función se define sin guardas, de ésta manera:

    + +
    siempreDiceLaVerdad alguien = esNiño alguien || esBorracho alguien
    +
    + +

    Ejemplo 3: No usar pattern matching

    + +

    A veces, cuando estamos aprendiendo guardas, nos olvidamos que poseemos Pattern Matching en Haskell.

    + +

    En otras palabras, podríamos tener una función así:

    + +
    ivaPara actividad | actividad == "cultural" = 0.0
    +                  | actividad == "alimentaria" = 10.5
    +                  | otherwise = 21.0
    +
    + +

    Cuando en realidad, con Pattern Matching, podría quedar más declarativo:

    + +
    ivaPara "cultural" = 0.0
    +ivaPara "alimentaria" = 10.5
    +ivaPara _ = 21.0
    +
    + +

    Otro ejemplo de lo mismo:

    + +
    longitud lista | null lista = 0
    +              | otherwise = 1 + longitud (tail lista)
    +
    + +

    Cuando quedaría más declarativo:

    + +
    longitud [] = 0
    +longitud (_:resto) = 1 + longitud resto
    +
    + +

    Ejemplo 4: “Hacer la guarda antes de tiempo” (Repetición de código)

    + +

    Cuando se repite código a ambos lados de la guarda, ésto es un problema:

    + +
    f a | a < 3     = 2 + 5 * g a
    +    | otherwise = 1 + 5 * g a
    +
    + +

    Que puede arreglarse así:

    + +
    f a = fAux a + 5 * g a
    +fAux a | a < 3 = 2
    +       | otherwise = 1
    +
    + +

    Nahuel Palumbo (El Rasta) denominó este tipo de repetición “Hacer el if antes de tiempo”, y sucede también en otros paradigmas y lenguajes.

    + +

    Ejemplo 5: Repetición de código más rebuscada

    + +

    También puede pasar que se repita código entre las guardas de esta manera:

    + +

    Se quiere saber el precio del boleto a partir de la cantidad de kms que voy a recorrer. Se sabe que a partir de 4 km, el cálculo del boleto es el cálculo máximo ($2 + $0.1 x cantidad de kms), mientras que hasta los 4km, el cálculo es el 110% del cálculo máximo

    + +

    Se propuso esta solución:

    + +
    precioBoleto kms | kms >= 4  = 2 + 0.1 * kms
    +                 | otherwise = 110 / 100 * (2 + 0.1 * kms)
    +
    + +

    Pero arriba y abajo se repite 2 + 0.1 * kms. En este caso, se arregla con la forma más común de corregir la repetición de lógica: delegando en ambos casos en la misma función.

    + +

    En otras palabras, si yo tengo:

    + +
    maximo kms = 2 + 0.1 * kms
    +
    + +

    Entonces esa lógica está ahora en un sólo lugar, que puedo llamar desde donde necesite:

    + +
    -- Solución final correcta:
    +precioBoleto kms | kms >= 4  = maximo kms
    +                 | otherwise = 110 / 100 * (maximo kms)
    +
    + +

    Hay otras formas mejores y peores de evitar éste tipo de repeticiones, pero ésta forma (delegando) es bastante buena y sirve en muchos casos.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/function-object.html b/wiki/articles/function-object.html new file mode 100644 index 0000000000..1a95931ad7 --- /dev/null +++ b/wiki/articles/function-object.html @@ -0,0 +1,392 @@ + + + + + + + + + + + Function object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Function object +

    +
    + + + +
    +

    Entendemos por Function Object a un patrón funcional aplicado a objetos que consiste en cosificar el envío de mensajes, para poder resolver problemas empleando orden superior y aplicación parcial de forma similar a como lo haríamos en el paradigma funcional.

    + +

    El problema

    + +

    En el paradigma de objetos los mensajes no son objetos, y por tanto no tenemos forma de hablar contra los mensajes, mas allá de las capacidades reflexivas de algunos lenguajes. Dicho de otra forma los mensajes no son valores, no son “cosas”.

    + +

    Esto nos restringe en que no tenemos mucho control sobre estos envios: por ejemplo, no tenemos forma nativa de enviar mensajes parciales o de pasar el envío de un mensaje por parámetro.

    + +

    Por ejemplo, en Haskell, uno puede escribir los siguiente:

    + +
    map (1+) [1,2,3]
    +
    + +

    dado que las funciones están currificadas (lo cual se aprecia en la expresión 1+, donde se aplica parcialmente + con el valor 1, devolviendo otra función), y son valores (1+, es un valor que puede ser pasado como argumento a map)

    + +

    Si el envío de mensajes en Smalltalk fuera un valor, uno bien podría escribir lo siguiente:

    + +
    #(1 2 3) collect: (1+)
    +
    + +

    (omitiendo el argumento del mensaje +)

    + +

    o

    + +
    #(1 2 3) collect: (+1)
    +
    + +

    (omitiendo el receptor del mensaje + 1)

    + +

    Para suplir estas limitaciones, la estrategia usada en objetos consiste justamente en cosificar el envío de mensajes, construyendo objetos que lo modelen. En lenguajes como Smalltalk, tenemos una forma nativa de construir tales objetos: los bloques de código.

    + +

    Por ejemplo, en Smalltalk, la funcionalidad anterior se implementa de la siguiente forma:

    + +
    #(1 2 3) collect: [:x | x + 1]
    +
    + +

    Lo cual es análogo al siguiente código Haskell:

    + +
    map (\x -> x + 1) [1,2,3]
    +
    + +

    En el sentido de que explícitamente construye un valor que modela una computación, que los argumentos de la misma son explícitos y están etiquetados. Pero con la diferencia de que en Haskell, el uso de una lambda es redundante, mientras que en Smalltalk es necesario.

    + +

    Justamente por su semejanza con la definición de una función anónima, a este patrón se lo conoce como Function Object: un objeto que entiende en su versión más simple un único mensaje (llamado típicamente apply, value, call, eval, etc) y cosifica un envio de mensajes.

    + +

    Estos objetos pueden entender opcionalmente otros mensajes que permitan implementar la noción de aplicación parcial y/o currificación, y que implementen operaciones típicas sobre funciones como, por ejemplo, la composición.

    + +

    En lenguajes como Java, dónde no tenemos una sintaxis específica para instanciar estos bloques de código, tenemos que recurrir a la definición e instanciación explícita de clases, típicamente definiendo una o varias interfaces que representen a las funciones de diferentes aridades, e implementádolas e instanciandolas conjuntamente, mediante el uso de clases anónimas.

    + +

    Así por ejemplo, es común encontrar encontrar código que emplea bibliotecas (no estándares) de colecciones de la siguiente forma:

    + +

    java +Collections.map(Arrays.asList(1,2,3), new Function<Integer, Integer>() { +    public Integer apply(Integer x) { return x + 1; } +}); +`

    + +

    Lo cual es evidentemente mas verborrágico y tiene mucha mas redundancia que las soluciones anteriores, pero igualmente cumple su cometido.

    + +

    Function Object y Orden Superior

    + +

    Function Object y Closure

    + +

    Function Object, Strategy y Command

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/garbage-collector.html b/wiki/articles/garbage-collector.html new file mode 100644 index 0000000000..7f42c964de --- /dev/null +++ b/wiki/articles/garbage-collector.html @@ -0,0 +1,321 @@ + + + + + + + + + + + Garbage collector + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Garbage collector +

    +
    + + + +
    +

    El garbage collector es un mecanismo que provee la Máquina Virtual para manejar la memoria de forma transparente para el desarrollador. Cuando un objeto ya no es referenciado por ningún otro, deja de ser útil porque nadie puede mandarle mensajes. Si ya no es útil, está ocupando espacio innecesariamente, con lo cual el garbage collector se encarga de liberar ese espacio sin afectar al sistema.

    + +

    Al tener un garbage collector podemos evitarnos los problemas asociados al manejo manual de memoria que ocurren comunmente, por ejemplo, en lenguajes como C como liberar más de una vez la misma posición de memoria, leaks de memoria, etc. A su vez nos permite concentrarnos en los que nuestro programa debe hacer con un grado de abstracción más alto.

    + +

    Hay garbage collectors con diferentes estrategias, la más utilizada es la generacional que se basa en el hecho de que los objetos con mayor propensión a no ser necesitados nuevamente son los más nuevos (por ejemplo, el resultado de un cálculo que se usa en el momento y no se necesita más), a partir de esta idea es posible optimizar el algoritmo de recolección. Resolver esta problemática a mano para cada programa no sólo desvía nuestra atención del objetivo, además que sea igualmente o más eficiente que un algoritmo genérico y ampliamente probado es muy poco probable.

    + +

    Para la gente curiosa, acá hay un artículo simpático que muestra gráficamente distintos algoritmos de recolección: Visualizing Garbage Collection Algorithms

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/git--un-versionador-distribuido.html b/wiki/articles/git--un-versionador-distribuido.html new file mode 100644 index 0000000000..707e0dfbc2 --- /dev/null +++ b/wiki/articles/git--un-versionador-distribuido.html @@ -0,0 +1,404 @@ + + + + + + + + + + + Git un versionador distribuido + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Git un versionador distribuido +

    +
    + + + +
    +

    Distribuido…

    + + + + + + + + +
    Se dice de git que es un sistema de control de versiones distribuido. Que sea distribuido implica que van a existir al menos tantos repositorios como personas trabajando en el proyecto, a lo que se le pueden sumar uno o más repositorios que se usen como intermediarios para compartir cambios entre las distintas personas. Un lugar práctico para hostear repositorios públicos puede ser [https://github.com/gtihub]
    + +

    Repositorio

    + +

    Por repositorio se entiende el lugar donde se van guardando todas las versiones de un proyecto o de cada una de las cosas que forman parte de él.

    + +

    En el mundo git en vez de pensar en que cada archivo es una parte que va cambiando de versiones prefirieron pensar en que es todo el proyecto el que se va versionando entonces cada vez que se modifica una parte en realidad se está modificando todo el proyecto.

    + +

    Un proyecto no es otra cosa que una arbol de directorios y archivos donde la raíz del arbol es la carpeta raíz del proyecto. Este Arbol es lo que va cambiando a medida que avanza el proyecto.

    + +

    La forma en que git elige modelar el proyecto es como un arbol por lo que en el interior de un repositorio git van a existir tantos árboles como versiones distintas existan del proyecto. Estos árboles van a formar parte de un ¿DAG?

    + +

    DAG ¿lo qué?

    + +

    Veamos primero un dibujito:

    + +

    + +

    DAG es la forma cheta de decir grafo dirigido acíclico. O sea un dibujo con circulitos (nodos) y flechitas (vértices) que unen los circulitos sin que se pueda llegar al mismo círculo saltando de círculo en círculo siguiendo las flechitas que los unen.

    + +

    Un árbol es de por sí un DAG por lo que no tiene problemas en ser parte de un DAG más grande que lo contiene.

    + +

    Cada uno de los círculos representa un objeto almacenado en el repositorio (nodos en el DAG). Los rectángulos son referencias que sirven como punto de entrada a los objetos que viven en el repositorio, podrían considerarse parte del DAG pero están representados como rectángulos para diferenciar las referencias de los objetos almacenados.

    + +

    Los distintos colores de los circulos representan cada uno de los 4 tipos de objetos que existen:

    + +
      +
    • blob. Representa un archivo en el proyecto.
    • +
    • tree. Representa una carpeta en el proyecto, el primero corresponde al directorio raiz del proyecto o el mismísimo proyecto.
    • +
    • commit. La forma de agregar objetos al repositorio es con la operción commit. Esto agrega un objeto commit que tiene un vértice hacia un tree que representa al directorio raíz del proyecto. El sub-grafo que comienza en este tree representa el estado de todo el proyecto tras la ejecución del commit. En el dibujo se ve que los subgrafos que parten de cada commit comparten un objeto blob, esto significa que el commit B no modificó el archivo que agregó el commit A.
    • +
    + +

    El commit también conoce a su padre que es el commit que lo antecede, entonces los cambios que aplica un commit al proyecto son las diferencias entre el árbol al que apunta y el árbol al que apunta su padre. Cuando se ejecuta la operación merge se qenera un commit que tiene al menos dos padres entonces los cambios que aporta este commit depende de contra cual de sus padres se lo compare.

    + +
      +
    • tag. La operación tag genera un objeto tag en el repositorio y una referencia de tipo tag para accederlo.
    • +
    + +

    Un tag conoce un commit y a partir de este el estado del proyecto para ese commit. En su cuerpo también uncluye un título un comentario y opcionalmente se le puede agregar una firma gpg. Todos los objetos (círculos en el dibujo) tiene un nombre bastante feo para identificarlos (algo así como 8357799df0b47164c9726be6610ea1b7ed41ff32), este nombre es el resultado de aplicar un función de hash (SHA1) al objeto.

    + +

    Referencias: Las referencias son los rectángulos en el dibujo, son simplemente puntos de entrada a los objetos almacenados en el repositorio.

    + +
      +
    • Referencia de tipo tag (amarillo en el dibujo) apunta a un objeto de tipo tag y es inmutable, o más o menos inmutable.
    • +
    • Referencia de tipo branch (verde en el dibujo) apunta a un ojeto commit, es mutable y al commit al que apunta es al * último que se agregó para ese branch.
    • +
    • Referencia de tipo branch remoto (gris en el dibujo) es muy parecida a un branch sólo que se usa para seguir el estado de un branch en otro repositorio (recuerden que esto era distribuido). La del dibujo (origin/master) significa que sigue un branch llamdo master en un repositorio llamado origin. El nombre del repositorio es un shortcut de la url completa.
    • +
    • HEAD esta referencia la usa git para saber que commit será el padre del próximo commit, normalemnte apunta indirectamente a un commit a travez de un branch. Si almomento de ejecutar la operción commit el HEAD apunta a un branch el branch se actualiza para apuntar al nuevo commit.
    • +
    + +

    Todo muy lindo… ¿pero cómo lo uso?

    + +

    Bueno… primero lo tendrías que tener instaldo. Eso se explica acá. Ahora que git ya está git intalado y configurado podemos ver un ejemplo partiendo de un proyecto nuevo.

    + +

    En la consola (git bash si estás en windows)

    + +

    $ mkdir ~/prueba $ cd ~/prueba $ git init Lo que estamos haciendo es comenzar un proyecto cuya carpeta raíz será ~/prueba, y en esa carpeta inicializamos un repositorio git para mantener las versiones de nuestro proyecto de prueba. El repositorio está en una carpeta llamada .git adentro de la carpeta raíz del proyecto. La carpeta ~/prueba con todo su contenido menos la carpeta .git es lo que git llama working tree, algo similar a la working copy de svn.

    + +

    Git lo llama working tree porque un directorio en el file system que estemos usando es también un árbol y como git entiende los proyectos como árboles dice que la carpeta donde editamos los archivos del proyecto no es otra cosa que el árbol de trabajo.

    + +

    El repositorio no tiene todavía ningún objeto almacenado (círculos del dibujo) pero sí, tiene la referencia HEAD que apunta a ref/heads/master esto siginifica que apunta a un branch llamado master, el nombre master es el que se les ocurrio a los amigos de git para ponerle al branch principal, algo así como el trunk del svn. Un branch no es otra cosa que una referencia a un commit, pero como todavía no existe ningún commit tampoco existe el branch master. La referencia HEAD sirve para que git sepa en que branch estamos trabajando actualmente, lo que significa que al hacer el próximo commit actualizará el branch apuntado por HEAD. En este caso que todavía no se hizo ningún commit el branch master se creará con el primer commit.

    + +

    Vamos a crear nuestro primer commit

    + +

    $ cd ~/prueba #carpeta raíz del proyecto +$ touch unTexto.txt #creo un archivo +$ git add unTexto.txt #agrego el archivo al index de git +$ git commit -m "primer commit" #ejecuto la operación commit pasándole el comentario "primer commit"

    + +

    Basicamente la forma de trabajo es:

    + +

    Modifico el contenido del working tree (agrego y modifico archivos) Agrego alguno o todos los cambios al index (git add) Ejecuto un commit (git commit) Los cambios que aporta el commit es todo los que esté en el index. ¿Y qué es el index? Es un lugar donde voy acomodando los cambios que van a entrar en el próximo commit. También llamado staging, pero en casi toda la documentación de git aparece como index.

    + +

    como quedó el grafo de nuestro repo:

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/gradle.html b/wiki/articles/gradle.html new file mode 100644 index 0000000000..46dfd024bc --- /dev/null +++ b/wiki/articles/gradle.html @@ -0,0 +1,769 @@ + + + + + + + + + + + Introducción a Gradle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Introducción a Gradle +

    +
    + + + + + +
    +

    + Gradle logo +

    + +

    Introducción

    + +

    Gradle es una herramienta que ayuda a desarrollar un proyecto basado en el entorno de una JDK (Java, Kotlin, Xtend, Scala, Groovy, etc.) y que cumple con las siguientes funciones principales que vamos a explicar en las siguientes secciones:

    + +
      +
    • Reificación del Proyecto
    • +
    • Manejo de Dependencias a partir de repositorios locales y remotos
    • +
    • Plugins y tareas
    • +
    + +

    Reificación de Proyecto

    + +

    Java no trabaja la idea de proyecto, no lo representa como concepto, y eso se traslada a todos los lenguajes basados en la JDK. Entonces, cada uno de los IDEs pensados para Java agregan su propia forma de definirlo:

    + +
      +
    • en Eclipse tenemos los archivos .classpath y .project
    • +
    • en IntelliJ tenemos el directorio .idea
    • +
    • en Visual Studio Code tenemos la carpeta .vscode
    • +
    + +

    Gradle permite trabajar en cualquiera de estos IDEs con su propio modelo de proyecto, que se guarda en el archivo build.gradle.kts en el caso de trabajar utilizando el lenguaje Kotlin o build.gradle a secas, cuando la configuración se hace utilizando el lenguaje Groovy. A partir de ahora vamos a continuar la explicación asumiendo que estás usando Gradle con Kotlin.

    + +

    Identificación de un proyecto Gradle

    + +

    Todo proyecto en Gradle tiene tres cosas que lo identifican:

    + +
      +
    • group: representa la organización autora/dueña del artefacto. Por ejemplo, los proyectos de Algoritmos 2 suelen usar el groupId ar.edu.unsam.algo2.
    • +
    • artifact: este campo define el nombre por el que se conoce al proyecto en sí mismo. Algunos ejemplos: commons-collections, eg-seguros-kotlin, tp-futbol5-grupo01, etc.
    • +
    + +
    +

    Aclaración: los términos componente y artefacto son sinónimos de proyecto.

    +
    + +
      +
    • version: es el último componente del rompecabezas, dado que groupId:artifactId denota un único proyecto pero no alcanza para definir en qué versión del proyecto nos estamos parando. Se agrega entonces un número de versión para completar la información que Gradle necesita para generar una identificación unívoca. Conviene seguir las reglas de versionado semántico, para liberar versiones productivas. A veces se suele acompañar de un sufijo RELEASE (para versiones estables) o SNAPSHOT (para versiones intermedias que pueden estar sujetas a cambios).
    • +
    + +

    Gradle tomó de Maven, su antecesor directo, esta misma forma de identificar un proyecto. Vemos cómo se definen estos valores en el archivo build.gradle.kts:

    + +
    +
    +
    +      group = "ar.edu.unsam.algo2"
    +version = "1.0-SNAPSHOT"
    +
    +    
    +
    +
    + +

    El artifact se define en el archivo settings.gradle:

    + +
    +
    +
    +      rootProject.name = "eg-seguros-kotlin"
    +
    +    
    +
    +
    + +

    Manejo de dependencias

    + +

    Repositorios locales

    + +

    Las dependencias son útiles para poder acceder a códigos escritos por otros (como la biblioteca Mockk o Apache Commons Collections). Cuando instalamos Gradle, se crea un repositorio local en una carpeta que por defecto suele ser HOME/.gradle, donde descargamos los componentes localmente una sola vez (muchos proyectos que usan la misma dependencia van a buscar el artefacto en ese mismo lugar). Podemos encontrar al componente cuyo identificador es io.kotest:kotest-assertions-core:5.1.0 en

    + +
    +
    +
    +      ~/.gradle
    +   └── caches
    +        └── modules-2
    +             └── files-2.1
    +                    └── io.kotest
    +                          └── kotest-assertions-core
    +                                ├─ 4.4.3 (otra versión)
    +                                └─ 5.1.0 --> dentro de esta carpeta estará el artefacto
    +
    +    
    +
    +
    + +
      +
    • recordemos que el identificador de un componente se arma a partir del groupId + el artifactId + la versión
    • +
    • en la cache de Gradle están todos los componentes que descargamos localmente. Esto permite que cuando estemos trabajando en otro proyecto que comparta la misma dependencia no necesitemos ir a descargarla desde los repositorios. El comportamiento en una máquina Windows es exactamente igual, hay que explorar los directorios incluyendo los que son ocultos, y navegar a partir de la carpeta de usuario + \.gradle.
    • +
    + +

    Repositorios remotos

    + +

    Ahora bien, ¿desde dónde descargamos las versiones 4.4.3 y 5.1.0 de io.kotest:kotest-assertions-core? Existen para eso repositorios remotos donde se publican artefactos:

    + +
      +
    • Maven Central, que es el repositorio principal donde están subidos artefactos publicados con tecnología Maven. Las dependencias más importantes suelen estar en este repositorio y tenés una página de búsqueda de artefactos, muy útil cuando necesitamos bajarnos “Mockito”, “Log4J”, “Kotest” o cualquier otra dependencia.
    • +
    • para los proyectos en Kotlin, otro repositorio importante es el de Google (también en Maven) ya que contiene componentes relacionados con el desarrollo de Android, entre otros.
    • +
    • hay eventualmente otros repositorios remotos e incluso podés crear un servidor que funcione como repositorio de artefactos. Podés investigar Artifactory o JFrog, por el momento es suficiente con saber simplemente desde dónde estamos descargando nuestros componentes.
    • +
    + +

    En el archivo build.gradle.kts podés ver cómo se referencian los repositorios remotos:

    + +
    +
    +
    +      repositories {
    +    mavenCentral()
    +}
    +
    +    
    +
    +
    + +

    Definiendo dependencias en el proyecto

    + +

    Las dependencias se definen dentro de un tag dependencies:

    + +
    +
    +
    +      val kotestVersion = "5.1.0"
    +
    +dependencies {
    +    implementation(kotlin("stdlib"))
    +    testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion")
    +    testImplementation("io.kotest:kotest-assertions-core:$kotestVersion")
    +}
    +
    +    
    +
    +
    + +

    En este caso, estamos definiendo que nuestro proyecto tiene como pre-requisitos:

    +
      +
    • la biblioteca estándar de Kotlin
    • +
    • y los componentes kotest-runner-junit5 y kotest-assertions-core de io.kotest. La versión se define en una referencia val, el código que escribimos para definir el archivo de configuración es Kotlin.
    • +
    + +

    Una vez que hagamos un cambio en las dependencias, nos aparece el botón para sincronizar las definiciones del archivo con el IntelliJ, como vemos en este video:

    + +

    + descarga componente local +

    + +

    Al agregar una dependencia lo hacemos con el formato “group:artifact:version” y también definimos el tipo de alcance (scope), que puede ser

    + +
      +
    • implementation: el componente es necesario para hacer el build de nuestro proyecto.
    • +
    • testImplementation: el componente es necesario para ejecutar los tests de nuestro proyecto.
    • +
    • runtimeOnly: el componente se utiliza únicamente cuando tenemos levantada la aplicación. Esta variante es útil cuando trabajamos con objetos de resguardo (stubs o mocks) para ejecutar los tests (testImplementation) pero queremos tener un componente real que envía mails en la versión productiva (runtimeOnly).
    • +
    • otras variantes pueden estudiarse leyendo la documentación del plugin de Gradle para Java
    • +
    • custom: para les interesades dejamos un artículo que explica cómo definir configuraciones propias extendiendo el modelo de Gradle
    • +
    + +

    Resumen general del manejo de dependencias de Gradle

    + +

    + manejo de dependencias de gradle +

    + +

    Fuente: https://docs.gradle.org/current/userguide/dependency_management.html

    + +

    Al hacer el build de nuestro proyecto

    + +
      +
    • si la versión de ese componente se encuentra descargado en nuestro repositorio local, se utiliza como dependencia válida
    • +
    • en caso contrario habrá que buscar en los repositorios definidos en nuestro proyecto, como Maven Central, google, etc. en el orden en que fueron definidos
    • +
    • si en ninguno de los repositorios fue posible encontrarlo, entonces recibiremos un mensaje de error cuando intentemos hacer build del proyecto:
    • +
    + +

    + gradle componente fallido +

    + +

    Dependencias transitivas

    + +

    Un detalle no menor de la resolución de dependencias de Gradle es que también funciona para las dependencias transitivas.

    + +

    Por ejemplo:

    + +
      +
    • proyectoA –> proyectoB
    • +
    • proyectoB –> proyectoC
    • +
    • proyectoC –> proyectoD, proyectoE, proyectoF
    • +
    + +

    Al resolver las dependencias, el proyectoA necesitará descargar los componentes B, C, D, E y F. Incluso podríamos requerir diferentes versiones de los mismos componentes.

    + +


    +Noten que un proyecto comercial “normal” o mediano, puede incluir decenas y hasta cientos de dependencias. Esto se puede ver en IntelliJ desde la solapa Gradle, e inspeccionar

    + +
      +
    • compileClasspath: dependencias base para compilar los fuentes (que están en src/main/kotlin)
    • +
    • runtimeClasspath: dependencias que tendremos a la hora de ejecutar nuestra aplicación en Kotlin, que incluye dependencias runtimeOnly. En Algoritmos 2 no vamos a levantar ninguna aplicación, pero sí más adelante en Algoritmos 3.
    • +
    • testCompileClasspath: dependencias que incluyen tanto fuentes como las marcadas como testImplementation, que sirven para ejecutar los tests.
    • +
    + +

    + Gradle - Dependencias transitivas +

    + +

    Plugins

    + +

    Si bien Gradle provee una plataforma para poder facilitar el manejo de dependencias, el build del proyecto y muchas otras actividades más, quienes verdaderamente se encargan de esta tarea son los plugins, que terminan resolviendo cada una de estas cosas.

    + +

    Cada plugin permite

    + +
      +
    • definir qué elementos van a participar, extendiendo el modelo original de Gradle: por ejemplo el plugin de Kotlin configura la carpeta donde se ubican las clases principales en src/main/kotlin
    • +
    • crear tareas, como la compilación de todos los archivos Kotlin, o la ejecución de los tests unitarios indicando cuál es el framework, entre muchas otras cosas
    • +
    • agregar configuraciones a nuestro proyecto, como repositorios adicionales donde ir a buscar dependencias, o definir una versión de la JDK por defecto.
    • +
    + +

    Podés ver en cualquiera de nuestros ejemplos qué contiene la sección plugins del build.gradle.kts:

    + +
    +
    +
    +      plugins {
    +    kotlin("jvm") version "1.6.10"
    +    jacoco
    +}
    +
    +    
    +
    +
    + +

    En este ejemplo

    + +
      +
    • estamos utilizando una determinada versión del plugin de Kotlin para la JVM, para poder trabajar el proyecto adecuadamente en esa tecnología
    • +
    • y además se agrega JaCoCo (Java Code Coverage), que agrega tareas para poder escribir reportes de porcentaje de cobertura de nuestros tests que luego serán utilizados por sitios que los publican, como Codecov o Coveralls
    • +
    + +


    +Para más información pueden consultar esta página.

    + +

    Tareas

    + +

    Una tarea de Gradle no es otra cosa que una porción de código que se ejecuta en un determinado contexto. Por ejemplo, si escribimos en el archivo build.gradle.kts estas líneas de código:

    + +
    +
    +
    +      tasks.register("saludar") {
    +    doLast {
    +        println("Hola, qué tal?")
    +    }
    +}
    +
    +    
    +
    +
    + +

    Podemos ejecutarlo desde el menú de IntelliJ:

    + +

    + Gradle Task +

    + +

    Como se ve, es código Kotlin lo que se ejecuta.

    + +

    En particular, el plugin Kotlin define la mayoría de las tareas que vamos a utilizar:

    + +
      +
    • build construye el proyecto
    • +
    • jar sirve para empaquetar las clases y generar un Java ARchive, un zip de archivos .class
    • +
    • clean elimina carpetas temporales, algo útil previo a un build
    • +
    • test ejecuta las pruebas unitarias, algo que igualmente se hace también desde el IDE
    • +
    • y muchas otras tareas más que no hace falta conocer.
    • +
    + +

    Todas se pueden ejecutar de la misma manera que nuestra tarea custom saludar.

    + +

    Temas adicionales

    + +

    Gradle Wrapper

    + +

    En lugar de trabajar directamente con Gradle, cada proyecto en IntelliJ va a trabajar con un script genérico que constituye el Gradle Wrapper o wrapper a secas, que tiene algunas ventajas:

    + +
      +
    • no requiere instalación local de Gradle, con lo cual es más fácil estandarizar el proyecto y llevarlo a entornos de integración continua
    • +
    • permite trabajar cada proyecto con una versión particular de Gradle y actualizarla a futuro cuando lo deseemos
    • +
    + +

    La pregunta que podemos hacernos es: ¿esto cambia algo en mi forma de trabajar? No, en nada, pero es útil entender por qué utilizamos gradlew como ejecutable por consola en lugar de gradle, y qué hace esta estructura dentro de nuestro proyecto:

    + +
    +
    +
    +      .gradlew
    +.gradlew.bat
    +   └──gradle
    +        └──wrapper
    +            └──gradle-wrapper.jar
    +            └──gradle-wrapper.properties # link a la versión de Gradle que estamos usando
    +
    +    
    +
    +
    + +

    Para más información pueden ver esta página.

    + +

    Ejecutando gradle desde la consola

    + +

    Una alternativa es trabajar directamente con Gradle desde la consola, algo que puede ser útil para automatizar tareas, como cuando trabajemos con herramientas de integración continua.

    + +
    +
    +
    +      ./gradlew clean build
    +
    +    
    +
    +
    + +

    Esto ejecuta varios plugins en forma sincronizada:

    + +
      +
    • por un lado la tarea clean borra el directorio build donde estarán los archivos compilados
    • +
    • y luego compila los fuentes del proyecto, lo cual implica descargarse las dependencias, y compilar los archivos Kotlin a .class que una JRE pueda interpretar
    • +
    + +

    Si queremos ver el árbol de dependencias transitivas, podemos escribir

    + +
    +
    +
    +      ./gradlew -q dependencies 
    +
    +    
    +
    +
    + +

    Documentación oficial

    + +

    Para más información recomendamos leer

    + + + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/groovy-vs-scala.html b/wiki/articles/groovy-vs-scala.html new file mode 100644 index 0000000000..05bf65a501 --- /dev/null +++ b/wiki/articles/groovy-vs-scala.html @@ -0,0 +1,376 @@ + + + + + + + + + + + Groovy vs scala + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Groovy vs scala +

    +
    + + + +
    +

    Advertencia: Esta articulo tiene una cuota importante de subjetividad; no es una comparativa exacta. Así que tomalo con pinzas y recordá charlarlo con tu ayudante asignado.

    + +

    Para la materia diseño, ambas opciones son igualmente buenas. Te explico los pros (+), contras (-), y neutros (*) de cada una:

    + +

    Groovy:

    + +
      +
    • (+) Es sintácticamente el más simple. Se parece mucho a Ruby o pseudocódigo. Usa pocas palabras reservadas y el código es muy limpio.
    • +
    • (+) El metamodelo es similar al de Java: tiene clases, métodos, herencia, etc. Agrega mixins, pero también se codifican como clases. Tiene interfaces al estilo Java, pero no son necesarias. Esto te ayudará si querés usar el segundo cuatrimestre un fmwk de persistencia o presentación para la JVM (como los dos para los que damos soporte)
    • +
    • (+) Si vos y tu grupo quieren sacarle jugo, tiene cosas muy avanzadas y podés aplicar más técnicas de diseño. Por eso es que lo estamos usando para TADP
    • +
    + + + +
      +
    • (*) Tiene tipado dinámico e implícito (no escribís el tipo, los errores saltan en tiempo de ejecución). Podés usar también tipado explícito si querés (ponerle tipo a las variables), pero en la mayoría de los casos el chequeo de tipos seguirá ocurriendo en tiempo de ejecución, como en Smalltalk.
    • +
    • (*) Se usa bastante en el mercado, aunque son pocas las empresas que lo utilizan como su lenguaje principal; se suele usar en proyectos medianos o chicos mas que grandes (hay excepciones notables, como MercadoLibre). También se lo usa como herramienta complementaria para el testing y scripting.
    • +
    + + + +
      +
    • (-) Eventualmente, si bajas a mucho detalle, el metamodelo de Groovy es complejo y algo inconsistente. Y ocurrirán errores muy raros (que se pueden solucionar). Pero esto normalmente ocurre cuando lo usás a su límite y jugás mucho con técnicas de metaprogramación, cosa que no es el objetivo de diseño. Por eso, esto no debería ser problema, pero igual estás advertido.
    • +
    • (-) Para entender los mensajes de error en Groovy, es recomendable entender el metamodelo de Java. Por lo cual, una leída sobre este lenguaje, sus properties (getters y setters) y sobrecarga es una buena idea.
    • +
    + +

    Scala:

    + +
      +
    • (-) Es sintácticamente mucho mas complejo. De todas formas, el código en general es muy limpio, aunque hay excepciones, sobre todo en lo que concierne a tipos.
    • +
    • (-) El metamodelo está inspirado en el de Java, pero no es idéntico. Y es más complejo. Es un híbrido de objetos y funcional. Esto puede traer algunos problemas con algunos fmwks para la JVM; de todas formas, los que usarás en la materia (hechos por nosotros), deberían andar bien de una.
    • +
    + + + +
      +
    • (*) Tiene tipado estático e implícito (similar al de Haskell, tiene inferencia).Eso es bueno para detectar errores en el código pronto. De todas formas, su inferencia es más limitada que la de Haskell, por lo que tendrás que escribir más información de tipo que en Haskell, pero mucha menos que en lenguajes como Java o C.
    • +
    + + + +
      +
    • (+) Si tu grupo quieren sacarle el jugo, tiene cosas muy avanzadas (mucho más que Groovy). Es hoy en día uno de los lenguajes de programación más poderosos que existen y uno de los que más técnicas de diseño ofrece.
    • +
    • (+) El metamodelo, aunque complejo, es muy consistente, por lo que “todo cierra” y uno puede tener la tranquilidad de que si algo no funciona, es porque está haciendo algo mal y no porque hay un bug en el lenguaje.
    • +
    • (+) Aunque no es la panacea, en mi opinión, es uno de los lenguajes del futuro a mediano plazo (ya hay varias empresas que lo están usando de forma intensiva, ejemplo, Despegar.com).
    • +
    + +

    El resumen: ambos lenguajes me parecen buenos para la materia diseño. Y de ambos te podemos dar soporte. Mi consejo: hagan algunos experimentos, bájense los entornos, y vean cual les gusta más. Algunos links:

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/guia-de-instalacion-de-maven.html b/wiki/articles/guia-de-instalacion-de-maven.html new file mode 100644 index 0000000000..9b5cab5428 --- /dev/null +++ b/wiki/articles/guia-de-instalacion-de-maven.html @@ -0,0 +1,513 @@ + + + + + + + + + + + Guia de instalacion de maven + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Guia de instalacion de maven +

    +
    + + + +
    +

    + image +

    + +

    Introducción

    + +

    Maven es una herramienta que permite automatizar tareas de los desarrolladores, y facilitar el manejo de dependencias, la configuración de entornos de trabajos locales, entre muchas otras cosas. Por defecto, al instalar Eclipse también viene el plugin para utilizar Maven, pero a veces es necesario ejecutar instrucciones adicionales por consola y para eso son estas instrucciones.

    + +

    Instalación en Windows

    + +

    Recomendamos seguir este tutorial, ignorando la versión de JDK que es indistinta.

    + +

    Instalación en SO Unix-based (Linux, Solaris y Mac OS X)

    + +

    Mediante apt-get

    + +
    +
    +
    +      sudo apt-get install maven
    +sudo ln -s /usr/share/maven3/bin/mvn /usr/bin/mvn
    +
    +    
    +
    +
    + +

    Vale la pena aclarar que si bien este método es ms simple, generalmente las versiones de repositorio de Ubuntu suelen estar atrás de las vigentes. Igualmente no les va a traer problemas.

    + +

    Manualmente

    + +

    Descargar Apache Maven 3 desde este link.

    + +

    Descomprimir el tarball y mover el directorio a donde usualmente se guardan los programas. Ejemplo: /home/john/programs/.

    + +
    +
    +
    +      tar -xzvf apache-maven-3.6.0-bin.tar.gz
    +mv apache-maven-3.6.0 /home/john/programs/
    +
    +    
    +
    +
    + +

    Agregar la siguiente línea al archivo .bashrc. Este archivo oculto (su nombre empieza con ‘.’) contiene comandos que se ejecutan cuando se abre una terminal (consola). Se puede abrir con cualquier editor de textos (gedit, vim, emacs, notepad++, etc) y se encuentra en el directorio home del usuario.

    + +
    +
    +
    +      export PATH=$PATH:$HOME/programs/apache-maven-3.5.0/bin
    +
    +    
    +
    +
    + +

    Una forma sencilla de hacer ésto (sin tener que abrir un editor) es usando el programa echo y agregando al final del archivo el valor ingresado. Prestar atención al hecho de que se usan dos signos mayor:

    + +
    +
    +
    +      echo 'export PATH=$PATH:$HOME/programs/apache-maven-3.5.0/bin' >> .bashrc
    +
    +    
    +
    +
    + +

    Chequeos posteriores a la instalación

    + +

    Corroboramos que podemos usar Maven. El output sería algo parecido a éste:

    + +
    +
    +
    +      john@notebook:~mvn -v
    +Apache Maven 3.5.0 (r...)
    +Maven home: /home/john/programs/apache-maven-3.6.0
    +Java version: 1.8...
    +Java home: /usr/lib/jvm/...
    +Default locale: en_US, platform encoding: UTF-8
    +OS name: "linux", version: "3.0.0-19-generic", arch: "i386", family: "unix"
    +
    +    
    +
    +
    + +

    Configuración de Maven

    + +

    Por defecto no necesitás hacer nada, la configuración por defecto está bien para comenzar a trabajar. Pero en caso de ser necesario algunos ajustes, tenés que mirar el archivo settings.xml, que por defecto se ubica en

    + + + +

    Propiedades de Maven en Eclipse

    + +

    Window > Preferences te permite configurar algunas propiedades para Maven. Te recomendamos

    + +
      +
    • tener chequeado “Do not automatically update dependencies from remote repositories” para que no intente bajarte permanentemente nuevas versiones de los componentes que utilices. Esto requiere que lo hagas en forma manual, algo que quizás sea más recomendable.
    • +
    • tener chequeado “Download artifact sources” te permite ver el código fuente de los .jars que te bajes, esta opción hace que las descargas inicialmente tarden un poco más de tiempo pero es bueno cuando tenés algún error y necesitás entender cómo funciona alguna parte de un componente.
    • +
    • también es bueno chequear “Download artifact javadocs” para obtener documentación de los componentes que utilizamos
    • +
    • Y por último tener deschequeada la opción “Update Maven projects on startup” permite que manualmente vos actualices los proyectos solamente ante un cambio y no cuando levantes el Eclipse.
    • +
    + +

    Una configuración más que puede ser útil para encontrar versiones nuevas de artefactos en los repositorios es dejar chequeada:

    + + + +

    Material

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/guia-de-instalacion-de-rails.html b/wiki/articles/guia-de-instalacion-de-rails.html new file mode 100644 index 0000000000..dd3c6269b8 --- /dev/null +++ b/wiki/articles/guia-de-instalacion-de-rails.html @@ -0,0 +1,451 @@ + + + + + + + + + + + Guia de instalacion de rails + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Guia de instalacion de rails +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Guia de Instalación de Rails

    + +

    Introducción

    + +

    Ruby On Rails es, entre otras cosas, un framework de presentación Web MVC, que utiliza el lenguaje de programación Ruby. Para instalarlo, hay que instalar primero Ruby, algunas herramientas de desarrollo estándar de esta tecnología, y finalmente, Rails.

    + +

    Antes de empezar

    + +
      +
    • Este tutorial asume que ya seguiste la Guía de Instalación de Ruby
    • +
    • Este tutorial asume que estás trabajando en un entorno Linux. Si bien Ruby funciona en Windows, no se recomienda usar Rails en este sistema operativo.
    • +
    + +

    Pasos

    + +

    Instalar Rails

    + +

    + gem install rails +

    + +

    Crear un Proyecto

    + +

    + rails new  + +`cd ` +

    + +

    Configurar la versión de Ruby

    + +

    Por ejemplo:

    + +

    + rbenv local 2.0.0-p481 +

    + +

    Problemas Frecuentes

    + +

    No se puede instalar SQLITE3

    + +

    Si tienen un error de este estilo:

    + +

    + Gem::Ext::BuildError: ERROR: Failed to build gem native extension. +

    + +

    /usr/bin/ruby1.9.1 -r ./siteconf20140902-24182-zuispu.rb extconf.rb  +/usr/local/lib/site_ruby/1.9.1/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- mkmf (LoadError)

    + +

     An error occurred while installing sqlite3 (1.3.9), and Bundler cannot continue. + Make sure that `gem install sqlite3 -v '1.3.9'` succeeds before bundling.

    + +

    Verifiquen que instalaron ruby usando rbenv, y rbenv usando rbenv-installer, como explica Guia de Instalación de Ruby. No usen apt-get para instalar ninguno de estos componentes

    + +

    No se puede instalar libv8

    + +

    Si tienen un error de este estilo:

    + +

     ERROR:  Error installing libv8: +   ERROR: Failed to build gem native extension. +       /usr/bin/ruby1.9.1 extconf.rb + /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- mkmf (LoadError) +   from /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require' +   from extconf.rb:1:in `<main>' +  Gem files will remain installed in /var/lib/gems/1.9.1/gems/libv8-3.11.8.0 for inspection. +  Results logged to /var/lib/gems/1.9.1/gems/libv8-3.11.8.0/ext/libv8/gem_make.out

    + +

    Verifiquen lo mismo que en el título anterior.

    + +

    Falta el runtime de JS

    + +

    Si al intentar levantar el servidor con

    + +

    + rails server +

    + +

    Les dice que falta un “JavaScript Runtime”, descomenten en en Gemfile la línea que dice

    + +

    + gem 'therubyracer' +

    + +

    Y ejecuten de nuevo

    + +

    + bundle install +

    + +

    Más información

    + +

    + https://gorails.com/setup/ubuntu/14.04 +

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/guia-de-instalacion-de-ruby.html b/wiki/articles/guia-de-instalacion-de-ruby.html new file mode 100644 index 0000000000..c9b4f29f23 --- /dev/null +++ b/wiki/articles/guia-de-instalacion-de-ruby.html @@ -0,0 +1,422 @@ + + + + + + + + + + + Guia de instalacion de ruby + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Guia de instalacion de ruby +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Guía de Instalación de Ruby

    + +

    Introducción

    + +

    La siguiente es una guía de instalación de Ruby utilizando un gestión de versiones (rbenv). Si bien este no es estrictamente necesario, simplifica el proceso de instalación, y es además fundamental cuando se desea trabajar con múltiples versiones de Ruby, algo bastante común cuando se está trabajando en más de un proyecto Ruby en una misma computadora.

    + +

    Esta guía además instala algunas dependencias que en verdad son sólo necesarias para el framework Rails, pero de todas formas las incluimos porque son livianas, fáciles de instalar, y previenen problemas futuros.

    + +

    Pasos

    + +

    1. Instalar essentials

    + +

    + sudo apt-get install curl git build-essential libssl-dev autoconf bison libreadline6 libreadline6-dev zlib1g zlib1g-dev libsqlite3-dev sqlite3 +

    + +

    Explicación: varias herramientas y bibliotecas de Ruby necesitan bajar contenido de Internet, y compilar código nativo.

    + +

    2. Instalar RBENV

    + +

    Seguir las instrucciones en el repositorio de github de rbenv-installer. El resumen es:

    + +

    curl https://github.com/rbenv/rbenv-installer | bash +echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile +echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

    + +

    Explicación: Ruby suele cambiar bastante entre versiones, lo cual genera incompatibilidades. Para no tener problemas, se recomienda instalar Ruby a través de un manejador de versiones, que además de simplificar el proceso, permite usar versiones diferentes de esta tecnología en cada proyecto.

    + +

    Nota: Si usan Ubuntu y lo anterior no funciona revisen estas instrucciones https://github.com/sstephenson/rbenv#installation

    + +

    3. Verificar que se haya instalado rbenv

    + +

    + echo $PATH  +

    + +

    La linea ~/.rbenv/bin tiene que estar presente. Si no lo está, asegúrense de que el código del punto 2 se agregó correctamente en .bashrc o .bash_profile, y de que hayan reiniciado la terminal.

    + +

    4. Instalar una versión de Ruby y dejarlo como opción por defecto

    + +

    rbenv install 2.0.0-p481 +rbenv global 2.0.0-p481 +rbenv rehash

    + +

    Explicación: con esto instalamos una versión concreta de Ruby, y la dejamos lista para ser utilizada.

    + +

    5. Instalar Bundler

    + +

    + gem install bundler +

    + +

    Explicación: Bundler es una herramienta, que al igual que Maven, permite gestionar las dependencias de un proyecto.

    + +

    Problemas frecuentes

    + +
      +
    • No se reconoce el comando rbenv: asegúrense de que hayan reiniciado la terminal, y que hayan colocado el código de inicialización en el archivo correcto (.bashrc o .bash_profile, según qué Linux usen)
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/guiso-de-lentejas.html b/wiki/articles/guiso-de-lentejas.html new file mode 100644 index 0000000000..519a87536b --- /dev/null +++ b/wiki/articles/guiso-de-lentejas.html @@ -0,0 +1,359 @@ + + + + + + + + + + + Guiso de Lentejas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Guiso de Lentejas +

    +
    + + + +
    +

    Receta para 8 a 10 personas (12 a 15 porciones, la gente repite)

    + +
      +
    • 1.5kg de carne repartido a gusto entre: +
        +
      • chorizo colorado (no puede faltar)
      • +
      • panceta (no puede faltar)
      • +
      • carne de vaca, por ejemplo roast beef
      • +
      • carne de cerdo, por ejemplo bondiola
      • +
      • (opcional) salchicha parrillera
      • +
      +
    • +
    • 1kg de lentejas
    • +
    • 0.5 kg de cebolla
    • +
    • 2 papas
    • +
    • 2 batatas
    • +
    • 1/2 calabaza
    • +
    • 2 morrones (uno rojo y uno verde)
    • +
    • 3 zanahorias
    • +
    • cebolla de verdeo
    • +
    • Condimento a gusto +
        +
      • sal
      • +
      • pimienta
      • +
      • pimenton dulce
      • +
      • ají molido
      • +
      +
    • +
    • Queso rallado para el plato
    • +
    + +

    Preparación:

    +
      +
    1. Saltar la carne, de a poco, la idea es que esté dorada y si metemos todo de una no va a pasar. +Si podemos hacer esto sin que se queme el fondo, lo vamos a poder aprovechar en la cocción. +Reservar lo ya saltado para más adelante, +separando las carnes que requieren más cocción (roast-beef, bondiola) de los chorizos, panceta o salchichas. +
        +
      • Antes de saltar la carne la podemos cortar en pedazos del tamaño de un bocado.
      • +
      • Ojo con cortar los chorizos demasiado chicos porque se pueden deshacer del todo.
      • +
      +
    2. +
    3. Poner a hervir las lentejas, con la papa, batata y calabaza. +
        +
      • Para ganar tiempo, uno puede poner a hervir casi al mismo tiempo que comienza a saltar la carne +y apenas saltaste el roast beef y la bondiola los tirás a la olla también.
      • +
      • No hace falta ser muy puntilloso al cortar la verdura, +los pedazos más chiquitos van a desaparecer en el guiso y los grandes quedan. +Sólo tener en cuenta que el pedazo más grande tiene que ser un bocado razonable.
      • +
      +
    4. +
    5. Una vez saltada toda la carne, en el fondo de cocción saltar la cebolla, con un poco de sal. +
        +
      • De la cebolla de verdeo, poné sólo la parte blanca, las hojas verdes las ponemos al final de todo.
      • +
      • Vamos raspando un poquito el fondo que la cebolla se lleva todo el fondo de cocción de la carne, +el fondo de la olla tiene que quedar limpio en esta operación.
      • +
      +
    6. +
    7. Cuando el ácido de la cebolla haya sacado todo lo que había pegado en el fondo de cocción de la carne, +echar el morrón y la zanahoria. +
        +
      • Cortá la zanahoria bastante chica para que no te quede dura, daditos de menos de 1cm.
      • +
      +
    8. +
    9. Al mismo tiempo, ya podés poner la panceta y los chorizos en la olla principal, con las lentejas.
    10. +
    11. Cuando la cebolla esté lista, echar todo también el la olla principal.
    12. +
    13. Ahora es momento de verificar el condimento.
    14. +
    15. Dejalo hervir hasta que espese, si se ve el agua no es un guiso. +Espesa en parte porque el agua se evapora pero también porque parte de la verdura se deshace.
    16. +
    17. Apagalo y mezclale las hojas verdes de la cebolla de verdeo.
    18. +
    19. Es mejor dejarlo reposar un rato en la olla, igual en este momento está tan caliente que no lo podés comer, +dale 5 o 10 minutos.
    20. +
    21. Idealmente servir en cazuelas y comer con cuchara.
    22. +
    23. No olvidarse de ponerle queso rallado.
    24. +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/herencia.html b/wiki/articles/herencia.html new file mode 100644 index 0000000000..25d5709708 --- /dev/null +++ b/wiki/articles/herencia.html @@ -0,0 +1,557 @@ + + + + + + + + + + + Herencia + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Herencia +

    +
    + + + +
    +

    La herencia es un mecanismo que tiene por objetivo principal el compartir lógica/código similar. Esto lleva a evitar la duplicación de lógica/código. Cuando un objeto recibe un mensaje, mediante Method lookup buscará el comportamiento requerido en la clase de la cual es instancia y, en caso de no tener un método para el mismo, en sus superclases.

    + +

    Herencia Simple

    + +

    Una clase tiene siempre una superclase pero solo una.

    + +

    Lenguajes que implementan este tipo de herencia: Smalltalk, Java, C#, entre muchos otros

    + +

    Herencia Múltiple

    + +

    Una clase puede tener más de una superclase.

    + +

    Lenguajes que implementan este tipo de herencia: C++, Eiffel

    + +

    Generalización

    + +

    Empezamos con dos clases, Golondrina (con una variable de instancia energia) y Picaflor (con una variable de instancia energia) , definimos métodos para ambos

    + +

    Smalltalk

    + +
    #Golondrina
    +    >> energia
    +         ^energia
    +    >> come: gramos
    +         "Una golondrina aumenta su energia en cuatro veces los gramos ingeridos"
    +         energia := energia + (gramos * 4)
    +    >> vola: kms
    +         "Una golondrina disminuye su energia en 1 Joule por cada kilometro recorrido + 10 Joules que utiliza para el despegue "
    +         energia := energia - (kms + 10)
    +
    + +
    #Picaflor
    +    >> energia
    +         ^energia
    +    >> come: gramos
    +         "Un picaflor aumenta su energia en cuatro veces los gramos ingeridos"
    +         energia := energia + (gramos * 4)
    +    >> vola: kms
    +         "Un picaflor disminuye su energia en 1 Joule por cada kilometro recorrido + 20 Joules que utiliza para el despegue "
    +         energia := energia - (kms + 20)
    +
    + +

    Wollok

    + +
    class Golondrina {
    +  var energia
    +  method energia() {
    +    return energia
    +  }
    +  method come(gramos){
    +    //Una golondrina aumenta su energia en cuatro veces los gramos ingeridos
    +    energia = energia + (gramos * 4)
    +  }
    +  method vola(kms) {
    +    // Una golondrina disminuye su energia en 1 Joule por cada kilometro recorrido + 10 Joules que utiliza para el despegue
    +    energia = energia - (kms + 10)
    +  }
    +}
    +
    + +
    class Picaflor {
    +  var energia
    +  method energia() {
    +    return energia
    +  }
    +  method come(gramos){
    +    //Un picaflor aumenta su energia en cuatro veces los gramos ingeridos
    +    energia = energia + (gramos * 4)
    +  }
    +  method vola(kms) {
    +    // Un picaflor disminuye su energia en 1 Joule por cada kilometro recorrido + 20 Joules que utiliza para el despegue
    +    energia = energia - (kms + 20)
    +  }
    +}
    +
    + +

    Lo que nos permite la idea de generalización utilizando herencia es crear nuevas abtracciones.

    + +

    En el código de arriba nos podemos dar cuenta que tanto las golondrinas como los picaflores saben decirnos su energia, comer y volar.

    + +

    Ahora bien, las golondrinas y los picaflores (por ejemplo) saben comer pero además comen de la misma forma. Estaría bueno poder generalizar eso, si las únicos pajaritos con los que estoy trabajando son golondrinas y picaflores puedo decir que todas las aves comen de la misma forma. Entonces generalizo el concepto de Golondrina y Picaflor utilizando una nueva abstracción, como necesito poner en esa abstracción métodos y definir atributos nada mejor que esa nueva abstracción sea una nueva clase

    + +

    Smalltalk

    + +
    #Ave >> come: gramos
    +         "Un ave aumenta su energia en cuatro veces los gramos ingeridos"
    +         energia := energia + (gramos * 4)
    +
    + +

    Wollok

    + +
    class Ave {
    +  method come(gramos){
    +    //Un ave aumenta su energia en cuatro veces los gramos ingeridos
    +    energia = energia + (gramos * 4)
    +  }
    +
    + +

    Pero no puedo poner ese código en la clase Ave porque esa clase no tiene una variable de instancia energia.

    + +

    Si todas las aves tienen que tener una variable de instancia es algo que me gustaría dejar escrito solo en Ave.

    + +

    Smalltalk

    + +
    Ave tiene definida una variable de instancia energia
    +
    + +

    Wollok

    + +
    class Ave {
    +  var energia
    +  ....
    +
    + +

    ¿Cómo sigue esto?

    + +

    Tengo que explicitar que las golondrinas tienen todo el comportamiento que esta en la clase Golondrina y también tienen el comportamiento que está en la clase Ave. Además tengo que explicitar que los picaflores tienen todo el comportamiento que esta en la clase Picaflor y también tienen el comportamiento que está en la clase Ave.

    + +

    Esto se hace diciendo que Ave es superclase de Golondrina y Ave es superclase de Picaflor; además tenemos que eliminar el código repetido de las clases Golondrina y Picaflor.

    + +

    Smalltalk

    + +

    En Smalltalk la forma de crear una clase es enviándole el mensaje #subclass:instanceVariableNames:classVariableNames: (o uno similar, depende del dialecto de Smalltalk utilizado) a la superclase de la clase que queremos crear.

    + +
    Superclass
    +   subclass: #NameOfSubclass
    +   instanceVariableNames: 'variableInstancia1 variableInstancia2 variableInstanciaN'
    +   classVariableNames: 'variableClase1 variableClase2 variableClaseN'
    +
    + +

    En nuestro ejemplo

    + +
    Object
    +  subclass: #Ave
    +  instanceVariableNames: 'energia'
    +  classVariableNames: ''.
    +
    + +
    Ave 
    +  subclass: #Golondrina
    +  instanceVariableNames: ''
    +  classVariableNames: ''.
    +
    + +
    Ave 
    +  subclass: #Picaflor
    +  instanceVariableNames: ''
    +  classVariableNames: ''.
    +
    + +

    Wollok

    + +

    En Wollok, lo ponemos directamente en la definición de las clases, usando la palabra clave inherits:

    + +
    class Ave {
    +  var energia = 0
    +  method come(gramos){
    +    //Un ave aumenta su energia en cuatro veces los gramos ingeridos
    +    energia = energia + (gramos * 4)
    +  }
    +
    + +
    class Picaflor inherits Ave {
    +  method vola(kms) {
    +    // Un picaflor disminuye su energia en 1 Joule por cada kilometro recorrido + 20 Joules que utiliza para el despegue
    +    energia = energia - (kms + 20)
    +  }
    +}
    +
    + +
    class Golondrina inherits Ave {
    +  method vola(kms) {
    +    // Una golondrina disminuye su energia en 1 Joule por cada kilometro recorrido + 10 Joules que utiliza para el despegue
    +    energia = energia - (kms + 10)
    +  }
    +}
    +
    + +

    Clase abtracta

    + +

    En el ejemplo anterior la clase Ave se está usando como superclase de Golondrina y Picaflor. Si nosotros queremos instanciar un ave deberíamos elegir si será una golondrina o un picaflor para mandarle el mensaje new a alguna de esas clases. Lo que no sería correcto es:

    + +

    Smalltalk:

    + +
    unAve := Ave new.
    +
    + +

    Wollok:

    + +
    var unAve = new Ave()
    +
    + +

    Este código va a funcionar en principio, pero si yo considero que un ave tiene que poder volar y no hay una implementación en Ave para esta operación ya que está definido de formas diferentes en sus subclases, unAve no va a entender el mensaje.

    + +

    Entonces, una clase abstracta es aquella que no tiene sentido instanciar porque es demasiado genérica y no tiene una implementación concreta para algunos mensajes que debería entender porque está definido en sus subclases.

    + +

    Una buena práctica para formalizar el contrato de lo que es ser un ave es definir los métodos faltantes en la clase Ave de la siguiente forma:

    + +

    Smalltalk

    + +
    #Ave >> vola: unosKilometros
    +         self subclassResponsibility
    +
    + +

    Cuando un objeto recibe el mensaje #subclassResponsibility se produce un error indicando que el método debería redefinirse en alguna subclase.

    + +

    Wollok

    + +

    Se indica con la palabra clave abstract antes del método

    + +
    class Ave {
    +  abstract method vola(unosKilometros)
    +  ....
    +}
    +
    + +

    De esa forma si agregamos otra subclase de Ave, como ser Gaviota, y olvidamos redefinir vola, cuando una instancia de Gaviota reciba ese mensaje el error será más descriptivo que el error de no entender el mensaje, y el desarrollador sabrá que las gaviotas deberían definir su forma de volar.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/herramientas-de-desarrollo-con-android.html b/wiki/articles/herramientas-de-desarrollo-con-android.html new file mode 100644 index 0000000000..387bc82b1b --- /dev/null +++ b/wiki/articles/herramientas-de-desarrollo-con-android.html @@ -0,0 +1,423 @@ + + + + + + + + + + + Herramientas de desarrollo con android + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Herramientas de desarrollo con android +

    +
    + + + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    LogCat

    + +

    Para poder mostrar información en consola, hay que reemplazar los println por

    + +
    +
    +
    +         Log.v() // Verbose`
    +   Log.d() // Debug`
    +   Log.i() // Info`
    +   Log.w() // Warning`
    +   Log.e() // Error`
    +
    +    
    +
    +
    + +

    y

    + +
    +
    +
    +         Log.wtf
    +
    +    
    +
    +
    + +

    que muestran los errores por el LogCat, una consola especial de Android.

    + +

    Cómo usarlo

    + +
    +
    +
    +      Log.w("Librex", libro.toString());
    +
    +    
    +
    +
    + +

    El primer parámetro indica la aplicación o agrupador, la segunda es el valor a mostrar

    + +

    Cuándo usar cada uno

    + +

    Leer esta recomendación

    + +

    Notificaciones al usuario

    + +

    El concepto toast permite enviar al frente un mensaje al usuario sin la incomodidad que tiene el popup de tener que confirmar la lectura de ese mensaje. Es una herramienta útil tanto para informar acciones que corrieron en background como para mostrar el estado de la aplicación en modo desarrollo.

    + +

    Para más información

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/herramientas-de-instanciacion.html b/wiki/articles/herramientas-de-instanciacion.html new file mode 100644 index 0000000000..b9a69a8f23 --- /dev/null +++ b/wiki/articles/herramientas-de-instanciacion.html @@ -0,0 +1,343 @@ + + + + + + + + + + + Herramientas de instanciación + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Herramientas de instanciación +

    +
    + + + +
    +

    Llamamos instanciación a la creación de un objeto a partir de una clase, la cual define cuál es el comportamiento y los atributos que debería tener dicha instancia.

    + +

    Los mecanismos para instanciar objetos a partir de una clase varían bastante entre los distintos lenguajes. En particular, en aquellos lenguajes en los cuales las clases no son a su vez objetos (como Wollok y Java por porner algunos ejemplos) se proveen herramientas para instanciar objetos que se escapan un poquito de la mecánica más común de trabajo que es la de enviarle un mensaje a un objeto.

    + +

    En general, desde el punto de vista del uso, lo que los lenguajes proveen es una forma de crear cada instancia indicando cuál es la clase que se está instanciando y, en caso de que sea necesario, con qué valores debe inicializarse la instancia en cuestión. De esa forma, el objeto ya estará listo para su uso desde el momento de la creación.

    + +

    A continuación se detallan algunas herramientas de construcción a modo de referencia.

    + +

    Inicialización directa

    + +

    Este es el mecanismo disponible en el lenguaje Wollok en su versión actual. Permite crear instancias de una clase parametrizando los valores iniciales para los atributos que correspondan usando parámetros nombrados. Supongamos que tenemos una clase Golondrina con un atributo energia, cuyo valor por defecto es 100:

    + +
    class Golondrina {
    +  var energia = 100
    +  // ... todos los otros métodos para las golondrinas, 
    +  // entre los cuales habrán muchos que trabajen con la energía asumiendo que está inicializada con algún valor numérico
    +}
    +
    + +

    Podemos crear una instancia de la clase Golondrina manteniendo el default para la energía de esta forma: new Golondrina(). Si nos interesara crear una golondrina con 25 de energía, la inicialización directa permite parametrizar esta información de esta forma: new Golondrina(energia = 25), y el default simplemente no se usará.

    + +

    En caso de haber varios atributos, pueden inicializarse tantos como querramos, por ejemplo: new Direccion(calle = "Amenabar", numeracion = 140). No importa el orden en el cual se indiquen estos parámetros, solamente debe coincidir con el nombre del atributo que se está inicializando.

    + +

    Esta herramienta, combinada con buenos defaults en caso de que existan, permite construir objetos listos para usar de forma sencilla y con muy poca burocracia.

    + +

    Constructores

    + +
    +

    Nota: Los ejemplos que se muestran a continuación son en el lenguaje Wollok en sus versiones previas a la 1.8, sólo a modo ilustrativo.

    +
    + +

    Los constructores son métodos especiales cuya finalidad es la creación de objetos de la clase indicada con la inicialización de estado interno correspondiente. Para invocarlos se usa la palabra reservada new seguido por el nombre de la clase y los parámetros según corresponda. Este es el mecanismo que se puede encontrar en varios lenguajes industriales muy usados, como Java y C#, y también fue el mecanismo soportado por el lenguaje Wollok en sus primeras versiones (luego se deprecó intrudiciendo el mecanismo de inicialización directa).

    + +

    En general esta forma de definir lógica de inicialización permite definir más de un constructor con distinta cantidad de parámetros, de modo que se permita al usuario elegir la forma más adecuada para crear las instancias. Por ejemplo, las fechas podrían permitir instanciarse con un constructor sin parámetros retornando la fecha del día de hoy (porque es muy común querer obtener instancias con esa configuración particular, entonces se considera como la inicialización por defecto si no se indica nada), o con otro de 3 parámetros para que al instanciar la fecha se la inicialice con el día, el mes y el año deseados:

    + +
    new Date() // retornaría la fecha de hoy
    +new Date(22,10,2016) // retornaría la fecha para el día, mes y año especificados.
    +
    + +

    Esto permite que siempre que obtengamos un objeto, el mismo ya esté en condiciones de ser usado en vez de requerir que el usuario recuerde indicar los valores necesarios uno por uno mediante setters, teniendo mientras tanto un objeto con un estado inválido que no puede ser usado.

    + +

    Si no definimos ningún constructor, por defecto la clase viene con un constructor vacío implícito para poder crear los objetos haciendo, por ejemplo: new Golondrina()

    + +

    Supongamos que queremos construir golondrinas con una cantidad de energía que nosotros elijamos como valor inicial, podríamos definir:

    + +
    class Golondrina {
    +  var energia
    +  
    +  constructor(_energia){
    +    energia = _energia
    +  }
    +  // ... todos los otros métodos para las golondrinas, 
    +  // entre los cuales habrán muchos que trabajen con la energía asumiendo que está inicializada con algún valor numérico
    +}
    +
    + +

    Al definir ese constructor, el constructor vacío por defecto ya no estará disponible para instanciar objetos, de esa forma sólo podremos crear objetos con un estado interno válido en base al constructor particular que hayamos definido.

    + +

    Si el lenguaje que usás usa constructores para definir cómo se inicializan las instancias, asegurate de investigar no sólo cuestiones sintácticas, sino también qué recaudos hay que tener respecto a la herencia.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/herramientas-utiles.html b/wiki/articles/herramientas-utiles.html new file mode 100644 index 0000000000..fed52c0494 --- /dev/null +++ b/wiki/articles/herramientas-utiles.html @@ -0,0 +1,341 @@ + + + + + + + + + + + Herramientas utiles + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Herramientas utiles +

    +
    + + + +
    +

    Primeros pasos

    + + + +

    Mis plugins de eclipse

    + +

    TexLipse
    +Para edición de latex: http://texlipse.sourceforge.net/

    + +

    Sysdeo.
    +Permite manejar el Tomcat desde dentro del eclipse, se lo baja de: http://www.eclipsetotale.com/tomcatPlugin/tomcatPluginV321.zip.

    + +

    Rinzo.
    +Plugin de eclipse para editar XML y HTML, y se puede bajar de http://sourceforge.net/projects/editorxml/.

    + +

    Tomcat-XT.
    +Extensión al plugin de sysdeo para facilitar la interacción con Tomcat, lo pueden bajar de acá: http://sourceforge.net/projects/uqbar-tomcat-xt/.

    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/high-order-functions-and-variational-calculus.html b/wiki/articles/high-order-functions-and-variational-calculus.html new file mode 100644 index 0000000000..0cc50352e9 --- /dev/null +++ b/wiki/articles/high-order-functions-and-variational-calculus.html @@ -0,0 +1,331 @@ + + + + + + + + + + + Orden superior y calculo variacional (Referencia Externa) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Orden superior y calculo variacional (Referencia Externa) +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Introduction

    + +

    Shamessly taken from http://web.archive.org/web/20070209204638/http://ergodicity.iamganesh.com/2006/08/07/higher-order-functions/

    + +

    Higher order functions

    + +

    Joel Spolsky, of the JoelOnSoftware fame, recently wrote about higher order functions in “modern” languages. While these features have existed for decades in functional programming languages, they have gained a lot of attention lately due to Google’s MapReduce technology.

    + +

    Simply put, map and reduce are primitives in languages such as lisp. Thinking in terms of lists (naturally), map lets you apply a function to every element of a list, while reduce lets you combine values of the list in some way. Pick up any lisp book for more details on this programming paradigm.

    + +

    I find a great deal of similarity between functionals in programming, and functionals in variational calculus. Unfortunately, variational calculus is a much neglected field of calculus specially at the undergraduate level. Variational calculus lets you define “functions of functions.” For example, the functional defined for the continuous function y(t) in the region [a,b]:

    + +

    + +

    + +

    is the area under the y(t) curve. See how J is completely independent of y(t)? That’s the power of variational calculus.

    + +

    In general, if we have functions of the form:

    + +

    + +

    + +

    we can use the Euler-Lagrange equations to derive a differential equation to solve the problem.

    + +

    Variational calculus finds much use in diverse fields such as aerospace control (optimize a trajectory based on fuel cost), operations research (optimize FedEx’s drop off targets based on distance travelled), and image inpainting (total variational models). If you haven’t figured it out yet, “optimization” is the reason this entry is posted under Numerical.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/home.html b/wiki/articles/home.html new file mode 100644 index 0000000000..f51ebc3b17 --- /dev/null +++ b/wiki/articles/home.html @@ -0,0 +1,305 @@ + + + + + + + + + + + Home + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Home +

    +
    + + + +
    +

    Las Homes son objetos que representan a un conjunto de objetos. Hay situaciones donde hay requerimientos que no son propios de ningún objeto en particular sino del conjunto de los mismos. De ahí surge la necesidad de tener un objeto que permita representar ese concepto y poder así agregarle esa responsabilidad.

    + +

    De allí se desprende que las Homes son objetos que tienen cierta lógica de negocio que aplica a todo un conjunto (por ejemplo en el ejercicio de Atención Médica, la HomePrestadores es un buen lugar para poner el mensaje getPrestadoresDisponibles ya que itera sobre todos los Prestador). Pero no debería convertirse en un God Object, sino que debería delegar en algún punto en otros objetos. En general deberían sólo tener la lógica que aplica a nivel de grupo para luego delegar en los objetos que contiene.

    + +

    Tampoco se debe confundir la Home con el punto de entrada a todos los casos de uso. Los casos de uso deberían comenzar desde el objeto de negocio que corresponda, que puede o no ser una Home.

    + +

    La idea de Home no tiene que ver con performance, o base de datos.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/html.html b/wiki/articles/html.html new file mode 100644 index 0000000000..33f144f9fd --- /dev/null +++ b/wiki/articles/html.html @@ -0,0 +1,526 @@ + + + + + + + + + + + Html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Html +

    +
    + + + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    HTML

    + +

    HTML (HyperText Markup Language) es el lenguaje principal que se utiliza para construir páginas web. Es un lenguaje declarativo que permite describir el contenido de una página.

    + +

    Estructura General de una página HTML

    + +

    Sintaxis

    + +

    El HTML es un lenguaje de etiquetas o marcas. Por cada etiqueta que abre hay otra igual pero que cierra, se escribe igual pero con una “/” adelante.

    + +
    +
    +
    +      <html>
    +</html>
    +
    +<h3>
    +</h3>
    +
    +    
    +
    +
    + +

    La notación inline permite abrir y cerrar el tag en un mismo paso:

    + +
    +
    +
    +      <img />
    +<br/>
    +<hr/>
    +
    +    
    +
    +
    + +

    Si bien muchos browsers relajan la sintaxis de apertura y cierre de tags (como en los casos de <ul> y <br>) es una buena práctica respetar esta idea, lo que permite definir XHTML o HTMLs “bien formados”.

    + +

    Tag HTML

    + +

    Cada tag puede tener

    + +
      +
    • contenido, que es un texto
    • +
    • atributos, demarcados con una clave y un valor
    • +
    • otros tags, que se anidan en forma jerárquica
    • +
    + +
    +
    +
    +      <tag atributo1="valor1" atributo2="valor2">
    +    contenido con <otrotag>otro subcontenido</otrotag>
    +</tag>
    +
    +    
    +
    +
    + +

    + htmlStructure +

    + +

    Estructura de una página HTML

    + +

    El contenido de una página web se estructura en forma jerárquica. A partir de HTML 5 tenemos tags especiales que permiten definir una semántica estándar para nuestro documento:

    + +
      +
    • un encabezado o header principal de la página
    • +
    • el cuerpo principal o body, que arma el contenido de la página y puede agrupar tags visuales y los de contenido, como +
        +
      • section y article: que sirven como elementos que agrupan contenido, y que pueden a su vez tener elementos head, footer o nuevos section/article
      • +
      • nav: que contiene links de navegación
      • +
      • aside: elementos que no forman parte del contenido principal
      • +
      +
    • +
    • un pie de página o footer principal de la página
    • +
    + +

    + htmlContent +

    + +

    Ejemplo

    + +

    Un ejemplo posible de estructuración del body de una página puede ser:

    + +
    +
    +
    +      <section>
    +  <h1>El pato</h1>
    +  <section>
    +    <h1>Introducción</h1>
    +    <p>En esta sección, ampliaremos nuestro concepto del pato.</p>
    +  </section>
    +  <section>
    +    <h1>Hábitat</h1>
    +    <p>Esta especie de animal llegó en tiempos remotos, traídos en diversas expediciones desde Europa y China, se fueron expandiendo por todo el mundo rápidamente y debido a su temperamento fueron criados como animales domésticos para el consumo de su carne y huevos, así como para mascotas en muchos hogares.</p>
    +  </section>
    +   <aside>
    +    <p>otros estudiosos del pato</p>
    +  </aside>
    +</section>
    +<footer>
    +  <p>(c) 2010 The Example company</p>
    +</footer>
    +
    +    
    +
    +
    + +

    Análisis semántico de un HTML

    + +

    Esto permite que haya plugins como el HTML 5 Outliner que pueda ordenar los elementos según su orden de importancia (la jerarquía la define el nivel de anidamiento dentro de HTML pero también el tag le dice semánticamente a qué corresponde cada contenido).

    + +

    + html5Outliner +

    + +

    Aquí vemos que algunas páginas están semánticamente mejor ordenadas que otras: a veces no hay un título que identifique la sección, o no se respeta bien el orden jerárquico de los contenidos.

    + +

    En Firefox tenemos el add-on headingsMap que construye una estructura en paralelo para navegar las páginas de otra manera (para por ejemplo ordenar las noticias según las más leídas):

    + +

    + headingsMap +

    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/hugs-trex-insertfield-not-in-scope.html b/wiki/articles/hugs-trex-insertfield-not-in-scope.html new file mode 100644 index 0000000000..7dcbe3aa99 --- /dev/null +++ b/wiki/articles/hugs-trex-insertfield-not-in-scope.html @@ -0,0 +1,311 @@ + + + + + + + + + + + Hugs trex insertfield not in scope + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Hugs trex insertfield not in scope +

    +
    + + + +
    +

    Si están en Hugs y luego de cargar su programa aparece el siguiente error:

    + +

    Haskell 98 does not support extensible records ERROR - Hugs.Trex.insertField not in scope

    + +
      +
    • +
        +
      • Possible cause: “Hugs.Trex” module not imported
      • +
      +
    • +
    + +

    Revisen que en sus funciones no estén usando = para comparar dentro de la definición de una función. Para comparaciones por igualdad se usa ==

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/igual-o-identico-----vs---.html b/wiki/articles/igual-o-identico-----vs---.html new file mode 100644 index 0000000000..20ac9565dc --- /dev/null +++ b/wiki/articles/igual-o-identico-----vs---.html @@ -0,0 +1,377 @@ + + + + + + + + + + + Igualdad vs. Identidad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Igualdad vs. Identidad +

    +
    + + + +
    +

    Definiciones

    + +

    Identidad: decimos que dos objetos son idénticos si son el mismo objeto. Dentro del ambiente podemos tener dos referencias diferentes al mismo objeto. En Wollok el operador usado para comparar dos objetos por identidad es ===.

    + +

    Igualdad: (o equivalencia) por defecto dos objetos son iguales si son idénticos, o sea si son el mismo objeto. A diferencia de la identidad, la igualdad puede ser redefinida con una implementación específica si el problema lo amerita. En Wollok el operador usado para comparar dos objetos por igualdad es ==.

    + +

    Ejemplos

    + +

    Algunos objetos literales como los números o los booleanos son únicos en el sistema, por ese motivo evaluar 3 === 3 da true al igual que 3 == 3.

    + +

    Sin embargo, lo normal es hacer las comparaciones con == y no con ===, ya que en general lo que interesa saber es si dos objetos son iguales desde el punto de vista de dominio. Un ejemplo muy común son los strings: supongamos que queremos saber si el resultado de concatenar “hola” con “mundo” es el string “holamundo”. No es relevante si el resultado de esa concatenación fue exactamente el mismo objeto que se puede obtener al escribir el literal “holamundo”, de hecho, es normal que no lo sea:

    + +
    > "hola" + "mundo" == "holamundo"
    +=> true
    +> "hola" + "mundo" === "holamundo"
    +=> false
    +
    + +

    Dando un paso más, ¿en qué casos podría ser útil redefinir la igualdad? Hay algunos objetos que tienen como principal objetivo representar datos más allá de los literales que ya conocemos, como ser las fechas. Si evaluamos esto en una consola:

    + +
    > const fecha1 = new Date(day = 24, month = 11, year = 2017)
    +> const fecha2 = new Date(day = 24, month = 11, year = 2017)
    +
    + +

    Luego podemos confirmar que la igualdad para las fechas está definida en términos de los datos, la identidad no es relevante:

    + +
    > fecha1 == fecha2
    +=> true
    +> fecha1 === fecha2
    +=> false
    +
    + +

    Importante Sólo debería redefinirse la igualdad basado en valores que no vayan a cambiar. Por ejemplo si quisiéramos modelar una dirección que tiene como atributos la calle y la numeración y nos interesara definir la igualdad en esos términos, es importante que una vez construido el objeto dirección con la calle y la numeración, no sea posible cambiar esas referencias, ya que la relación de igualdad entre dos objetos debería mantenerse a lo largo del tiempo. O sea, el objeto no necesita ser totalmente inmutable pero sí debemos garantizar que mínimamente lo sea respecto a los valores usados para la igualdad.

    + +

    Otra cosa a tener en cuenta si se redefine la igualdad es que podrían existir otros objetos del sistema (como las colecciones) que se basan en otro mensaje (suele llamarse hash o hashCode) para encontrar rápidamente objetos que son (o podrían ser) iguales al receptor de dicho mensaje, es común que se use para algoritmos de búsqueda. Su particularidad es que, en vez de recibir otro objeto por parámetro para poder compararlo, no recibe parámetros y retorna un número al que se denomina código de hash. En general si la igualdad se define de una forma particular y se mantiene la forma de calcular el código de hash predefinida, eventualmente surgirán comportamientos inesperados. Por eso, independientemente de la tecnología que uses, asegurate de averiguar cúal es la forma más adecuada de implementar ese mensaje.

    + +

    En el caso del ejemplo planteado de las direcciones, podría ser razonable que la igualdad se defina preguntando si la calle de la dirección que recibió el mensaje es igual a la calle de la otra dirección y además la numeración de esa dirección también es igual a la numeración de la otra dirección. Luego el código de hash podría obtenerse mediante un cálculo que involucre tanto al código de hash de la calle de la dirección que recibió el mensaje y también al código de hash de su numeración.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/inferencia-de-tipos.html b/wiki/articles/inferencia-de-tipos.html new file mode 100644 index 0000000000..d58226ca2d --- /dev/null +++ b/wiki/articles/inferencia-de-tipos.html @@ -0,0 +1,423 @@ + + + + + + + + + + + Inferencia de tipos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Inferencia de tipos +

    +
    + + + +
    +

    Entendemos por inferencia de tipos la capacidad que tienen algunos lenguajes con chequeo estático de tipos para calcular el tipo de una expresión, función o variable sin necesidad de contar con anotaciones de tipo como sí se necesitan en C y Java por ejemplo.

    + +

    La clave de este proceso es la regla por la cual se obtiene el tipo de la aplicación de una función:

    + +
    f :: AB  ->  e :: A
    +-------------------
    +      f e :: B
    +
    + +

    En términos más mundanos, lo que la regla dice es:

    + +
      +
    1. si f es una función cuyo dominio es A e imagen es B y,
    2. +
    3. si e es una expresión de tipo A
    4. +
    5. entonces, el tipo de f e (usamos a e como argumento de f) es B
    6. +
    + +

    Ejemplo, el tipo de not False se puede inferir con esta regla:

    + +
      +
    1. si not es una función cuyo dominio es Bool e imagen es Bool y,
    2. +
    3. si False es una expresión de tipo Bool
    4. +
    5. entonces, el tipo de not False es Bool
    6. +
    + +

    Otro ejemplo, si queremos saber de que tipo es la expresión not 3 vemos que no tiene un tipo siguiendo la regla que especificamos anteriormente, porque requeriría que 3 sea de tipo Bool pero 3 no es un booleano.

    + +

    Expresiones como not 3, 2 + True, length (4,3), fst [1,2], etc. no tienen un tipo y por lo tanto no son expresiones válidas en Haskell. Analicemos el siguiente caso:

    + +
    funcionLoca x
    +  | x > 0 = 1
    +  | otherwise = True
    +
    + +

    Como por una rama retornamos un Int (1 :: Int) y por la otra retornamos un Bool (True :: Bool) no se puede obtener la imagen de la función funcionLoca, ergo la funcionLoca no se puede escribir en Haskell porque no tiene un tipo.

    + +

    Sin embargo, que una expresión tenga tipo no significa que sea una expresión libre de errores.

    + +
    head :: [ a ] -> a
    +head [] :: a
    +
    + +

    Pero a pesar de esto, si evaluamos la expresión

    + +
    > head []
    +Error
    +
    + +

    Como la inferencia de tipos es un proceso ANTERIOR a la evaluación, los programas que hacemos en Haskell son Type Safe

    + +

    ¿La inferencia de tipos es una característica del paradigma funcional?

    + +

    Sí, es un concepto que fue desarrollado primero en el contexto del paradigma funcional e históricamente se lo ha encontraro principalmente asociado a lenguajes funcionales; sin embargo la idea de inferencia no está limitada este tipo de lenguajes y cada vez más está siendo utilizada en todo tipo de lenguajes.

    + +

    Algunos lenguajes que poseen formas de inferencia de tipos son: Ada, BitC, Boo, C# 3.0, Cayenne, Clean, Cobra, D, Delphi, Epigram, F#, Haskell, haXe, JavaFX Script, ML, Mythryl, Nemerle, OCaml, Oxygene, Scala.

    + +

    Por otro lado, la inferencia es más simple en los lenguajes que no permiten realizar asignaciones; y eso hace que sea más fácil de implementar en los lenguajes declarativos puros como Haskell.

    + +

    Ejemplos

    + +

    Ver Cálculo del tipo de una función en Haskell

    + +

    Recuerden que en Haskell ustedes pueden obtener el tipo de cualquier expresión escribiendo :t (type) en el interprete

    + +
    > :t not
    +not :: Bool -> Bool
    +
    +> :t not False
    +not False :: Bool
    +
    +> :t not 3
    +Error
    +
    + +

    Problemas de inferencia en Haskell

    + +

    Si bien Haskell puede inferir correctamente el tipo de las funciones que definimos casi siempre, existen casos en los cuales necesita un poco de ayuda de parte del programador. En caso de que eso pase, conviene explicitar el tipo de nuestra función además de su definición en el .hs.

    + +

    Por ejemplo, si estamos haciendo una función f que recibe una lista de a y retorna una lista de a, podemos hacer:

    + +
    f :: [a] -> [a]
    +f lista = <lo que sea que hay que hacer con la lista para retornar otra>
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/inject-into-.html b/wiki/articles/inject-into-.html new file mode 100644 index 0000000000..68351ed268 --- /dev/null +++ b/wiki/articles/inject-into-.html @@ -0,0 +1,453 @@ + + + + + + + + + + + Inject into + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Inject into +

    +
    + + + +
    +

    El inject:into: es un solo mensaje que entienden todas las colecciones, recibe 2 parámetros.

    + +

      

    + +

    Utilidad

    + +

    La idea de este mensaje es realizar una operación de acumulación sobre todos los elementos de una colección.

    + +

    Parámetros del inject:into:

    + +

    El primero parámetro del inject:into: (valorInicialAcumulador) representa el objeto al cual va a apuntar el acumulador antes de empezar a evaluar el bloque (el 2do parámetro del inject:into:) sobre cada elemento de la colección.

    + +

    El segundo parámetro del inject:into: (bloqueConDosParametros) es un bloque que va a ser evaluado sobre cada elemento de la colección y el acumulador actual.

    + + + + + + + + +
    bloqueConDosParametros = [ :acumuladorActual :elementoDeLaColeccion \]
    + +

    El inject:into: retorna el valor final del acumulador

    + +

    Ejemplos

    + +

    Sumatoria de una colección de números

    + +

    Si col es una colección de números y queremos obtener su sumatoria podemos hacer

    + +

      col inject: 0 into: [ :sumatoria :numero | sumatoria + numero ]

    + +

    valorInicialAcumulador = 0

    + +

    acumulador = sumatoria

    + +

    elementoDeLaColeccion = numero

    + +

    operación que retorna el nuevo valor del acumulador = sumatoria + numero

    + +

    Productoria de una colección de números

    + +

    Si col es una colección de números y queremos obtener su productoria podemos hacer

    + +

      col inject: 1 into: [ :productoria :numero | productoria * numero ]

    + +

    valorInicialAcumulador = 1

    + +

    acumulador = productoria

    + +

    elementoDeLaColeccion = numero

    + +

    operación que retorna el nuevo valor del acumulador = productoria * numero

    + +

    Máximo de una colección de números

    + +

    Si col es una colección de números y queremos obtener el máximo podemos hacer

    + +

      col inject: col anyOne into: [ :maximo :numero | maximo max: numero ]

    + +

    valorInicialAcumulador = col anyOne (algún elemento de la colección)

    + +

    acumulador = maximo

    + +

    elementoDeLaColeccion = numero

    + +

    operación que retorna el nuevo valor del acumulador = maximo max: numero

    + +

    La altura más alta de una colección de personas

    + +

    Si col es una colección de personas y queremos obtener la altura más alta

    + +

      col inject: col anyOne altura into: [ :maximaAltura :persona | maximaAltura max: persona altura ]

    + +

    valorInicialAcumulador = col anyOne altura (alguna altura de alguna persona de la colección)

    + +

    acumulador = maximaAltura

    + +

    elementoDeLaColeccion = persona

    + +

    operación que retorna el nuevo valor del acumulador = maximaAltura max: persona altura

    + +

    La persona más alta de una colección de personas

    + +

    Si col es una colección de personas y queremos obtener la persona más alta

    + +

      col inject: col anyOne into: [ :personaMasAlta :persona | personaMasAlta altura > persona altura ifTrue: [personaMasAlta] ifFalse: [persona] ]

    + +

    valorInicialAcumulador = col anyOne (alguna persona de la colección)

    + +

    acumulador = personaMasAlta

    + +

    elementoDeLaColeccion = persona

    + +

    operación que retorna el nuevo valor del acumulador = personaMasAlta altura > persona altura ifTrue: [personaMasAlta] ifFalse: [persona]

    + +

    Nota: si asumimos que persona es instancia de la clase Persona podemos hacer lo siguiente

    + +

      col inject: col anyOne into: [ :personaMasAlta :persona | personaMasAlta personaMasAlta: persona ]

    + +

      Persona >> personaMasAlta: otraPersona +    ^self altura > otraPersona altura +         ifTrue: [ self ] ifFalse: [ otraPersona ]

    + +

    Aplanando colecciones

    + +

    Si col es una colección donde cada uno de sus elementos son colecciones y quiero obtener una colección con todos los elementos de sus subcolecciones puedo hacer

    + +

      col inject: Bag new into: [ :unaColeccionConTodosLosElementos :unaColeccion | unaColeccionConTodosLosElementos addAll: unaColeccion. unaColeccionConTodosLosElementos ] "Hay que retornar explícitamente unaColeccionConTodosLosElementos"

    + +

    Si no nos interesan los elementos repetidos podemos escribir

    + +

      col inject: Set new into: [ :unaColeccionConTodosLosElementos :unaColeccion | unaColeccionConTodosLosElementos union: unaColeccion ]

    + +

    Al menos en Pharo recordar que:

    + +
      +
    • +

      #union: retonarna una instancia de Set

      +
    • +
    • +

      #add, #addAll:, #remove:, #removeAll: retornan el objeto que recibieron como parámetro NO retornan al objeto receptor del mensaje

      +
    • +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/inmutabilidad.html b/wiki/articles/inmutabilidad.html new file mode 100644 index 0000000000..4d7cf5902f --- /dev/null +++ b/wiki/articles/inmutabilidad.html @@ -0,0 +1,356 @@ + + + + + + + + + + + Inmutabilidad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Inmutabilidad +

    +
    + + + +
    +

    El concepto de inmutabilidad está asociado a la ausencia de cambio. En los paradigmas Funcional y Lógico, la inmutabilidad está garantizada, ya que no es posible modificar los datos con los que trabaja una función o un predicado, en todo caso lo que se puede hacer para emular un cambio sobre una estructura es retornar o relacionar con una nueva estructura a partir de la original con la información que tendría como consecuencia de la transformación deseada.

    + +

    Por ejemplo, si en Haskell quisiéramos representar que una persona de la cual conocemos su nombre y su edad cumpla un año tendríamos que definir una función como esta:

    + +
    data Persona = Persona String Int
    +cumplirAños :: Persona -> Persona
    +cumplirAños (Persona nombre edad) = Persona nombre (edad + 1)
    +
    + +

    En los paradigmas en los cuales se trabaja con efecto colateral trabajar de forma inmutable es una decisión de diseño. Pensemos un poco en el paradigma de objetos.

    + +

    Decimos que un objeto es inmutable si no puede cambiar su estado interno (su conjunto de atributos) después de su inicialización.

    + +

    Los Strings son un ejemplo de objetos inmutables, cualquier operación que hagan sobre un string (concatenación, cambiar a mayúscula o minúscula, etc) sólo retorna otro string, el receptor nunca se modifica.

    + +

    Si la interfaz del objeto tiene una forma de inicializar sus variables, pero no exhibe el comportamiento para settear sus atributos, sus usuarios no podrán alterar su estado interno más adelante. Para construir un objeto ya inicializado solemos usar métodos de clase u otras herramientas de instanciación, de esa forma no será necesario usar setters para configurar un estado que no sería esperable que cambie luego de la construcción del objeto.

    + +

    Que un objeto sea inmutable permite que pueda ser compartido por varios objetos sin que puedan afectarse entre sí, ya que no hay nada que puedan hacer sobre ese objeto compartido que produzca un cambio visible para el otro objeto que lo conoce.

    + +

    Es importante tener en cuenta que no alcanza en algunos casos con que el objeto no exhiba comportamiento que permita mutarlo, ya que podría tener un atributo que referencie a un objeto que sí es mutable. Luego si alguien le manda un mensaje que retorna a ese objeto mutable, y a ese objeto le manda un mensaje que lo modifica, el objeto inicial habrá sufrido cambios.

    + +

    Volviendo al caso de los Strings, estos objetos están compuestos por otros objetos que representan a los caracteres, qué pasa si al string ‘hola’ le pido su primer elemento y a ese caracter $h le mando un mensaje para que se cambie a mayúscula, luego el string original ya no sería ‘hola’ sino, ‘Hola’, no? Eso no es un cambio sobre el string también??

    + +

    Bueno, como resulta que los caracteres también son inmutables, realmente no hay nada que se pueda hacer para que el string cambie.

    + +

    Entonces, si estamos haciendo nuestros propios objetos inmutables, hay que tener en cuenta si los objetos que conocen pueden o no cambiar su estado. En el caso de que no, listo, pero si sí pueden, hay que plantearse si dichos objetos no deberían ser también inmutables, y en el caso de no querer que así sea, retornar copias de los mismos cuando sea necesario. De esa forma, quien envíe el mensaje que retorna uno de estos objetos mutables, pueda realizar modificaciones sobre el mismo sin que el objeto inmutable se vea afectado.

    + +

    Otra cosa a mencionar es sobre los objetos inmutables es que la igualdad ya no se basa en la identidad. Debería ser cierto por ejemplo que ‘hola’ sea igual a ‘ho’ concatenado con ‘la’, independientemente de que sean o no el mismo objeto. La igualdad termina dependiendo de los valores de sus atributos (o un subconjunto de ellos). Por eso es muy común redefinir la igualdad para los objetos inmutables.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/intro-a-colecciones.html b/wiki/articles/intro-a-colecciones.html new file mode 100644 index 0000000000..bfd5ed6a11 --- /dev/null +++ b/wiki/articles/intro-a-colecciones.html @@ -0,0 +1,440 @@ + + + + + + + + + + + Intro a colecciones + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Intro a colecciones +

    +
    + + + +
    +

    Las colecciones nos resultan de utilidad porque nos permiten agrupar objetos, para luego poder operar sobre un elemento en particular, sobre algunos elementos seleccionados mediante un filtro, o sobre una colección como conjunto.

    + +

    Esto nos permite modelar conjuntos o agregados de cosas, que son muy comunes en casi todos los dominios en los que podemos pensar: las piezas de un tablero de ajedrez, los integrantes de un equipo de fútbol, las líneas de una factura, ¡de todo!

    + +

    A primera vista una colección es un conjunto de objetos. Si la vemos con más precisión nos damos cuenta que es más preciso pensarla como un conjunto de referencias: los elementos no están adentro de la colección, sino que la colección los conoce. Y como no podía ser de otra forma, las colecciones también son objetos.

    + +

    No hay un único tipo de colección, hay distintos sabores de colecciones que nos van a servir para distintos fines, sin embargo la mayoría de las colecciones entiende un conjunto grande de mensajes en común, o sea, son polimórficas :) Sólo van a diferir en algunos mensajes particulares debido a la naturaleza de la colección.

    + +

    ¿Qué podemos hacer con una colección?

    + +

    Para tratar de responder esta pregunta no es necesario estar familiarizado con la implementación de las colecciones. Recordemos que una de las características ventajosas del Paradigma de Objetos es que acerca nuestro modelado a la forma en que percibimos la realidad.

    + +

    Entonces ¿que haríamos nosotros con una colección? Pensemos en una colección de estampillas. Podemos:

    + +
      +
    • Mirarlas -> recorrer la colección y hacer algo con cada elemento
    • +
    • Encuadernarlas por fecha -> ordenar la colección
    • +
    • Conseguir nuevas estampillas -> agregar elementos a la colección
    • +
    • Regalar una estampilla -> quitar elementos de la colección.
    • +
    • Quedarme con las estampillas de Brasil -> hacer un filtro o selección de los elementos según un criterio.
    • +
    • Saber si tengo una determinada estampilla -> preguntarle a una colección si incluye o no un determinado objeto como elemento.
    • +
    + +

    ¿Qué otra colección podemos modelar del mundo real? ¡¡Un carrito del supermercado!!

    + +

    Mientras vamos de góndola a góndola del super vamos agregándole elementos (referencias a objetos) a esa colección. Cuando llegamos a la caja recorremos esa colección y obtenemos información de la misma: cuánto suma el costo total de sus artículos, cuántos artículos compré…

    + +

    ¿Ahora, como podemos modelar todas estas situaciones en objetos?… ¡Enviando mensajes a colecciones! Recordemos que en el paradigma de objetos todo programa es un conjunto de objetos enviándose mensajes para concretar un objetivo en común. Bien, en este caso los objetos serán las distintas colecciones y sus elementos. Los mensajes que puede recibir una colección serán dependientes del lenguaje, claramente, pero la idea detrás es básicamente la misma.

    + +

    Un ejemplo rápido en Wollok: En este ejemplo vamos a usar un tipo de colección al que llamamos Set. Supongamos que tenemos 4 objetos distintos que son estampillas (nos interesa que nos sepan decir su origen y su superficie, no importa cómo lo hacen), agreguemos algunas a la colección.

    + +
    var coleccionEstampillas = #{}
    +coleccionEstampillas.add(estampillaBrasileraGrande)
    +coleccionEstampillas.add(estampillaAlemana)
    +coleccionEstampillas.add(estampillaBrasileraMediana)
    +
    + +

    Alternativamente, si ya conozco los elementos que va a tener inicialmente, usando el set literal de Wollok podemos crear directamente la colección con esos elementos.

    + +

    var coleccionEstampillas = #{estampillaBrasileraGrande, estampillaAlemana, estampillaBrasileraMediana}

    + +

    A esta colección de estampillas ya le puedo hacer algunas preguntas

    + +
    coleccionEstampillas.size() // devuelve 3
    +coleccionEstampillas.contains(estampillaAlemana) // devuelve true
    +coleccionEstampillas.contains(estampillaBrasileraChica) // devuelve false
    +
    + +

    Claro que para que la colección me sea realmente útil, me debe permitir interactuar con sus elementos, poder hablarle (p.ej.) a estampillaAlemana a través de la colección. Antes de ver cómo hacer esto, clarifiquemos un poco la relación entre una colección y sus elementos.

    + +

    Colecciones y referencias

    + +

    Como ya dijimos en la introducción, si miramos una colección en detalle, vemos que es mejor entenderla como un conjunto de referencias a objetos, y no como un conjunto de objetos. ¿Cuál es la diferencia? Que conceptualmente, la colección no tiene “adentro suyo” a sus elementos.

    + +

    Los elementos de una colección son objetos como cualesquiera otros, al agregarlos a una colección estoy, en realidad, agregando una referencia que parte de la colección y llega al objeto “agregado”. Los objetos que elijo agregar una colección pueden estar referenciados por cualesquiera otros objetos.

    + +

    En el ejemplo anterior, algunas de las estampillas que creamos son elementos de la colección, y además están referenciadas por variables. Gráficamente tenemos:

    + +

    Si se están preguntando ¿en qué orden “están” las estampillas en el Set? Un Set no mantiene sus elementos en un orden determinado, más adelante veremos que hay distintos “sabores” de colecciones, algunos mantienen orden y otros no. En este momento, no es lo que nos interesa.

    + +

    Ahora agreguemos un objeto más: pedro, el coleccionista, que sabe cuál es su estampilla favorita (la estampillaBrasileraMediana). El ambiente queda así:

    + +

    + +

    Ahora hay un objeto que tiene 3 referencias:

    + +
      +
    1. +

      es el objeto referenciado por la variable estampillaBrasileraMediana

      +
    2. +
    3. +

      es un elemento del Set

      +
    4. +
    5. +

      es la estampilla preferida de pedro

      +
    6. +
    + +

    Ya podemos ver un poco más en detalle la relación entre una colección y sus elementos. La colección maneja referencias a los elementos que le voy agregando (p.ej. enviándole el mensaje add(elemento) ), análogas a las referencias de las variables de instancia de otros objetos. Hay dos diferencias entre las referencias que mantiene una colección y las que mantienen nuestros objetos p.ej. pedro:

    + +
      +
    • Las referencia que usan nuestros objetos tienen un nombre, que es el nombre que luego usará para hablarle al objeto referenciado; las de la colección son anónimas.
    • +
    • Nuestros objetos tienen una cantidad fija de referencias (en este caso pedro tiene una única referencia, estampillaPreferida), una colección puede tener una cantidad arbitraria, que puede crecer a medida que le agrego elementos.
    • +
    + +

    Así, los objetos que quedan referenciados por la colección pueden tener otras referencias sin problema. Un objeto no tiene nada especial por ser elemento de una colección, sólo tiene una referencia más hacia él. Un objeto no conoce de qué colecciones es elemento (podría tener una referencia explícita a la colección para saberlo, pero eso habría que programarlo a mano y por lo general tampoco nos interesa).

    + +

    La referencia a un objeto por ser elemento de una colección cuenta para que el objeto no salga del ambiente cuando pasa el Garbage collector. Eso significa que si dejamos de referenciar a nuestra estampilla alemana mediante la referencia estampillaAlemana, como la colección de estampillas la conoce, el objeto va a seguir en el sistema.

    + +

    + +

    Hablando con los elementos

    + +

    Hay algunas operaciones que se hacen sobre una colección en las cuales parte de lo que hay que hacer es responsabilidad de cada elemento.

    + +

    Por ejemplo, supongamos que quiero obtener de mi colección de estampillas aquellas que tengan más de 10 cm2 de superficie. La colección no sabe la superficie de cada estampilla, sí conoce a las estampillas, entonces puede enviarle mensajes a cada una. Lo que no sabe es qué mensajes puede enviarle, un Set no sabe si lo que tiene son estampillas, perros, números, otros Set, o cualquier otro objeto, sólo representa al conjunto, sin saber nada de sus elementos. Por otro lado, cada estampilla no sabe en qué colección está, de hecho un mismo objeto podría estar en varias colecciones.

    + +

    Por lo tanto, para resolver mi problema necesito que actúen tanto la colección (que es la que conoce a los elementos) como cada elemento (que es el que sabe su superficie). Veamos cómo lograr esta interacción. Empecemos por decidir a quién le pedimos lo que queremos. Quiero aquellas estampillas, de las que son elementos de coleccionEstampillas, que cumplan una determinada condición.

    + +

    ¿A qué objeto le voy a pedir esto? A la colección.

    + +

    El mensaje es filter(algo) en Wollok…

    + +

    … o sea que necesita un parámetro. Este parámetro va a representar una condición para el filtrado, que es un código que la colección debería evaluar sobre cada elemento, y debe devolver true o false para que la colección sepa si debería o no estar en la colección nueva a devolver.

    + +

    Los objetos que representan “cachos de código” son los Bloques, en este caso un bloque con un parámetro

    + +

    coleccionEstampillas.filter({estampilla => estampilla.superficie() > 10})

    + +

    Mientras que todos los elementos de la colección entiendan el mensaje superficie y al recibirlo retornen un número, el filtrado va a funcionar correctamente.

    + +

    En resumen: cuando quiero hacer una operación sobre una colección que necesita enviarle mensajes a cada elemento, la operación se la pido a la colección, y le voy a enviar como parámetro un bloque que describe la interacción con cada elemento.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/introduccion-a-las-metodologias-de-desarrollo-de-software.html b/wiki/articles/introduccion-a-las-metodologias-de-desarrollo-de-software.html new file mode 100644 index 0000000000..d2982889c5 --- /dev/null +++ b/wiki/articles/introduccion-a-las-metodologias-de-desarrollo-de-software.html @@ -0,0 +1,410 @@ + + + + + + + + + + + Introduccion a las metodologias de desarrollo de software + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Introduccion a las metodologias de desarrollo de software +

    +
    + + + +
    +

    ¿Para qué sirve una metodología?

    + +

    Una metodología nos ordena, nos contiene, nos permite definir límites. Construir software complejo requiere un gran esfuerzo: tecnología, dinero y sobre todo: personas. Personas que interactúan entre sí, con diferentes grados de conocimiento, con diferentes roles, con diferentes intereses. Una metodología propone un esquema de trabajo que nos permite entender cuál es nuestro rol dentro del proyecto, nos acerca una cierta sensación de tranquilidad, de seguridad. Sin un proceso no sabemos cómo comenzar y cuándo terminar.

    + +

    Metodologías secuenciales / iterativas

    + +

    En las metodologías secuenciales, el proceso de desarrollo de software se divide en varios pasos o fases. Cada fase tiene un conjunto de metas a cumplir. El fin de cada fase delimita el comienzo de la fase siguiente. Aunque son normales la superposición de fases, estas metodologías proponen una gran fase de análisis de requerimientos, otra de diseño, otra de construcción y otra de pruebas donde el alcance de cada fase es la totalidad de los requerimientos de un proyecto.

    + +

    En las metodologías iterativas se divide el proyecto en entregas o iteraciones. Si cada iteración define un conjunto de metas a cumplir, podríamos pensar que no hay una gran diferencia con la metodología secuencial. No obstante, cada iteración define como entregable un software testeable por el usuario. Entonces hay etapas de análisis de requerimientos, diseño, construcción y prueba en cada iteración. Además, cada iteración permite revisar y cambiar los requerimientos a resolverse.

    + +

    Metodologías orientadas al proceso / a las personas

    + +

    Otra taxonomía que divide las metodologías es el grado de importancia que le dan

    + +
      +
    • al proceso de desarrollo
    • +
    • y a las personas que ejecutan ese plan
    • +
    + +

    Si bien la mayoría de las metodologías contemplan tanto la serie de pasos que conforman el proceso como qué tipo de tareas deben desarrollar las personas (en base a sus perfiles), hay metodologías en las que el proceso está por encima de las personas. Dicho de otra manera, “respetar el proceso garantiza el éxito del proyecto”. El margen de discrecionalidad (cuánto puedo salirme del libreto) es mínimo, sólo en lo operacional (en el día a día). Por eso es importante para estas metodologías poder medir cada tarea del proyecto, sea un ejecutable o documentación.

    + +

    Por el contrario, las metodologías orientadas a las personas consideran que éstas definen el éxito o fracaso de un proyecto. Les asignan un grado mayor de decisión en cada tarea y confían en su capacidad de resolución de un problema antes que en las métricas que dan los indicadores. Esto no quiere decir que el proceso no importe, sino que ocupa un puesto de menor relevancia en la consecución de un logro.

    + +

    Metodologías orientadas a la documentación / al producto

    + +

    Hay metodologías que sostienen que un producto de software bien elaborado nace de una documentación extensa y que contemple todas las decisiones que surgieron del análisis y del diseño. De esa manera el desarrollador no tendrá dudas ni excusas a la hora de escribir cada línea de código.

    + +

    Por el contrario, hay metodologías que privilegian tener un software testeable para el usuario antes que tener el documento que respalde ese software que está corriendo. Esto no significa que haya que programar sin tener una especificación, sino que:

    + +
      +
    • tomamos una documentación que puede tener definiciones pendientes, estar incompleta en su diseño o que sepamos que esté sujeta a cambios
    • +
    • construimos el software
    • +
    • y luego actualizamos las decisiones principales en el documento
    • +
    + +

    con la ventaja de tener la certeza de que lo que hace el sistema es eso.

    + +

    Metodologías predictivas / adaptativas

    + +

    ¿Qué ocurre con los cambios que piden los usuarios mientras se va construyendo el software? ¿Cómo se manejan?

    + +
      +
    • algunas metodologías creen que es posible anticipar los cambios a través de un buen análisis y un buen diseño que contemple diferentes alternativas. Este enfoque no es inocente, sabe perfectamente que el usuario puede cambiar de opinión, que las disposiciones legales e impositivas sufren modificaciones y que los proyectos están siempre sujetos a vaivenes políticos. Pero justamente por eso busca minimizar los cambios para conservar lo más estable posible el entorno: resistirse al cambio es su naturaleza.
    • +
    • otras metodologías consideran que el cambio es inevitable, que no tiene sentido resistirse a él. De manera que el proceso mismo contempla momentos en los que el usuario puede modificar los requerimientos: esto implica agregar nuevos, descartar otros o modificarlos (no importa si ya fueron construidos o no). “El usuario tiene derecho a cambiar de opinión”, sostienen.
    • +
    + +

    Algunos ejemplos

    + +
      +
    • Modelo de Cascada: nunca existió, fue una maliciosa interpretación del paper de Winston Royce: “Managing the development of large software systems”. Les recomendamos ver este interesante video al respecto, para entender lo inapropiado y excesivamente optimista que es aplicar esta metodología en un proceso de desarrollo actual.
    • +
    • Espiral de Boehm: originado en el paper de Barry Boehm: “A Spiral Model of Software Development and Enhancement”, surge como primer contracara del modelo de cascada. Sigue un modelo de planificación de objetivos, identificación de riesgos y desarrollo y verificación del producto en n iteraciones, +
        +
      • esto lo convierte en adaptativo (contempla cambios acomodándolos en el plan de las sucesivas iteraciones). Tomamos prestada una fase del artículo donde sostiene la importancia de que el proceso no fuerce al diseñador a tomar decisiones en forma anticipada: “[The spiral approach] fosters the development of specifications that are not necessarily uniform, exhaustive, or formal, in that they defer detailed elaboration of low-risk software elements and avoid unnecesary breakage in their design until the high-risk elements of the design are stabilized”.
      • +
      • El modelo de espiral tiene un contenido altamente orientado al proceso (en el artículo no hay una sola mención sobre el papel que juegan las personas dentro del proyecto)
      • +
      • No podemos afirmar que sea una metodología orientada al producto ni a la documentación, en cada iteración debemos armar el análisis de riesgo, relevar los requerimientos de sistema y de software, hacer el plan de la iteración siguiente, el diseño global y detallado y los casos de prueba, pero por otra parte también la iteración contempla la posibilidad de prototipar y exige la presentación de un software testeable para el usuario.
      • +
      +
    • +
    • Proceso unificado: comercializado por varias empresas, el proceso unificado es el primero que permite adaptarse según el tamaño del proyecto y su complejidad. Se autodefine como un proceso “iterativo e incremental, dirigido por los casos de uso, orientado a la arquitectura y que busca anticipar los riesgos del proyecto”. Las fases del proyecto se dividen en: Inception, Elaboration, Construction y Transition. Cada una es susceptible de dividirse en iteraciones y lo que diferencia una fase de otra es la madurez del producto que se está construyendo. +
        +
      • Desde la fase de Elaboración hay construcción, test y deploy de un ejecutable, por eso su naturaleza es iterativa.
      • +
      • De la misma manera, se evita tomar decisiones en forma prematura y se contempla la posibilidad de modificar los requerimientos hasta la última iteración, por lo que también encaja perfectamente en las metodologías adaptativas.
      • +
      • UP sugiere una gran cantidad de artefactos de documentación, aunque podemos minimizarlos para concentrarnos en el código funcionando para el usuario. En la discusión filosófica documentación vs. producto podemos decir que UP está a mitad de camino de ambas, como lo confirma esta frase: “El producto no es sólo el ejecutable, también es la documentación que acompaña al sistema: manual de usuario, casos de uso, diagramas de clase, diagrama de arquitectura, etc.”
      • +
      • Respecto a la orientación persona o proceso podemos decir que UP se mantiene en una zona gris. Por un lado define que “las personas son importantes y tienen que saber qué hacer”, mientras que al mismo tiempo cada persona cumple un rol que sugiere que esas personas están supeditadas a un proceso en el cual confiar.
      • +
      +
    • +
    • Metodologías ágiles: como extreme Programming, Scrum (según el artículo de Jeff Sutherland y Ken Schwaber, basado en el artículo original de Takeuchi, Hirotaka; Nonaka, Ikujiro), ASD, etc. Todas se basan en el manifiesto ágil que establece sus principios metodológicos para desarrollar software: +
        +
      • Las personas y cómo se relacionan entre sí son más importantes que los procesos y las herramientas tecnológicas (es orientado a las personas, por definición)
      • +
      • Un producto funcionando es más importante que la documentación exhaustiva (orientado al producto)
      • +
      • La colaboración del cliente es más importante que la negociación del contrato (que discrimina al cliente como parte externa del producto)
      • +
      • Responder al cambio es más importante que seguir el plan (adaptativo/iterativo)
      • +
      +
    • +
    + + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/java.html b/wiki/articles/java.html new file mode 100644 index 0000000000..7d8bd00412 --- /dev/null +++ b/wiki/articles/java.html @@ -0,0 +1,420 @@ + + + + + + + + + + + Java + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Java +

    +
    + + + +
    +

    Sobre el lenguaje:

    + + + +

    (Algunas) Herramientas basadas en Java:

    + + + +

    Persistencia

    + +
    +
    +
    +      -   [Hibernate](http://www.hibernate.org/)
    +-   [JDBC](http://en.wikipedia.org/wiki/Java_Database_Connectivity)
    +
    +    
    +
    +
    + +

    SCM (Software Configuration Management)

    + +
    +
    +
    +      -   Maven
    +    -   [Apache Maven](http://maven.apache.org/)
    +    -   [Maven (Wikipedia)](http://en.wikipedia.org/wiki/Apache_Maven)
    +
    +    
    +
    +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/javascript.html b/wiki/articles/javascript.html new file mode 100644 index 0000000000..d71a1ece7b --- /dev/null +++ b/wiki/articles/javascript.html @@ -0,0 +1,364 @@ + + + + + + + + + + + Javascript + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Javascript +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Sobre el lenguaje

    + + + +

    Herramientas basadas en JavaScript

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/jdkVsJre.html b/wiki/articles/jdkVsJre.html new file mode 100644 index 0000000000..0cfcb4e86d --- /dev/null +++ b/wiki/articles/jdkVsJre.html @@ -0,0 +1,357 @@ + + + + + + + + + + + JDK vs. JRE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + JDK vs. JRE +

    +
    + + + +
    +

    jdk set of tools

    + +

    Cuando nos piden “instalar Java” (a secas) en nuestra máquina, es importante tener en claro la diferencia entre:

    + +
      +
    • JRE o Java Runtime Environment: un conjunto de herramientas que permite ejecutar código compilado en Java. El environment o ambiente donde viven los objetos se implementa con la JVM (Java Virtual Machine).
    • +
    • JDK o Java Development Kit: incluye al JRE y además le agrega herramientas propias para desarrollar en Java: el compilador (javac), el generador de documentación html para las clases (javadoc), el debugger (jdb), entre otros.
    • +
    + +

    Para tener el listado completo de las herramientas que trae OpenJDK, recomendamos ingresar a esta página.

    + +

    Arquitectura general del entorno Java

    + +

    En este diagrama vemos el proceso de desarrollo de un programa Java desde que lo escribimos hasta que se ejecuta en una máquina (nuestra o de un usuario). Para compilar el programa Java a un código intermedio o bytecode necesitamos el ejecutable javac, que viene con el JDK. El archivo .class generado puede ser interpretado en cualquier otro sistema operativo, solo necesitamos tener el JRE adecuado. Ejecutamos entonces el programa java (o javaw en Windows) pasando como argumento nuestro archivo .class para que el bytecode sea interpretado al código de la máquina.

    + +


    +proceso de JDK +

    + +

    Eclipse integra todas estas herramientas de manera que cada vez que grabás un archivo Java realiza la compilación para generar el .class y ejecutarlo desde el mismo entorno. Por eso Eclipse es un IDE, o Integrated Development Environment.

    + +

    Desarrollo en Kotlin/JVM

    + +

    Haciendo la aclaración de que hay variantes de Kotlin que no necesitan la JDK (Kotlin Native o bien Kotlin/JS), en las materias Algoritmos 2, Algoritmos 3 y Programación con Herramientas Modernas trabajamos con Kotlin/JVM que precisan instalarse la JDK.

    + +

    De esa manera cuando generamos nuestro archivo .kt con el código fuente, el compilador automáticamente genera el bytecode asociado (el .class, que está en la carpeta build/classes/kotlin) utilizando tanto el compilador de Kotlin como las herramientas que trae la JDK.

    + +


    +proceso de desarrollo en Kotlin +

    + +

    Como estamos trabajando dentro de un IDE, este paso adicional es transparente para nosotros. Solo debemos tener en cuenta que además del plugin de Kotlin, necesitaremos tener instalada una JDK para que el proceso de fondo convierta los archivos .kt a .class.

    + +

    Como resultado, nuestros programas pueden ejecutarse utilizando la máquina virtual de Java a partir de cualquier JRE.

    + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/json.html b/wiki/articles/json.html new file mode 100644 index 0000000000..d10d3ac381 --- /dev/null +++ b/wiki/articles/json.html @@ -0,0 +1,391 @@ + + + + + + + + + + + json + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + json +

    +
    + + + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    JSON

    + +

    Introducción

    + +

    JSON (JavaScript Object Notation) es un estándar para expresar estructuras de datos en un subset del lenguaje javascript. Se hizo popular en los últimos tiempos como el estándar de formato para transferir información entre sistemas. El JSON es una estructura arbórea, donde cada objeto es un mapa o diccionario.

    + +

    Facebook, Twitter, Foursquare proveen una forma de acceder a su información (contactos, tweets, y lugares, respectivamente) que nos retorna la información en formato JSON. La idea es parecida a la idea de XML (asumiendo que ya conocen esta idea), pero menos verborrágico.

    + +

    Ejemplo de una persona

    + +

    Ejemplo de una persona en formato JSON:

    + +
      +
    • Un objeto es un conjunto de “clave-valor” entre llaves.
    • +
    • Las claves tienen nombres en strings (entre comillas)
    • +
    • Los valores pueden ser strings o números, o bien otras estructuras.
    • +
    • “telefonos” tiene como valor una lista o array, que se escribe con literales “corchetes”. Y elementos separados por comas.
    • +
    • “mascota” tiene como valor otro objeto JSON, que a su vez tiene sus propios atributos como clave-valor.
    • +
    + +
    +
    +
    +      {
    +  "nombre": "Juan",
    +  "apellido": "Pérez",
    +  "edad": 45,
    +  "telefonos": [
    +    47574933,
    +    29298122,
    +    88384831
    +  ],
    +  "mascota": {
    +    "nombre": "Colita",
    +    "tipo": "perro"
    +  }
    +}
    +
    +    
    +
    +
    + +

    Material complementario

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/juegos-de-estrategia.html b/wiki/articles/juegos-de-estrategia.html new file mode 100644 index 0000000000..faeb7bee70 --- /dev/null +++ b/wiki/articles/juegos-de-estrategia.html @@ -0,0 +1,337 @@ + + + + + + + + + + + Juegos de estrategia + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Juegos de estrategia +

    +
    + + + +
    +

    Modelo inicial

    + +

    Se desea modelar un juego de estrategia en el cual existen unidades que se pueden atacar las unas a las otras.

    + +

    Al atacar una unidad a otra, se compara el potencial ofensivo del atacante con el potencial defensivo del defensor. En caso que el primero sea mayor al segundo, la unidad atacada pierde tanta energía como la diferencia entre el potencial ofensivo y el defensivo involucrados. En otro caso, no ocurre nada.

    + +

    Por ejemplo, si un atacante con 30 de potencial ofensivo ataca a un defensor con 20 de potencial defensivo, este último pierde 10 de energia.

    + +

    Hay tres tipos de unidades:

    + +
      +
    • Guerreros -> Que pueden ser atacados o atacar. Tienen un potencial ofensivo específico cada uno y también su propio potencial defensivo. Comienzan con 100 unidades de energía.
    • +
    • Murallas -> Que pueden ser atacados pero no atacar. Tienen un potencial defensivo que equivale a su energía sobre 20, con un mínimo que depende de cada muralla. Comienzan con 1000 unidades de energía.
    • +
    • Misiles -> Que no pueden ser atacados pero pueden atacar. Su potencial ofensivo equivale a 100 multiplicado por la cantidad de kg de explosivos que tenga, que es propia de cada misil.
    • +
    + +

    Problemas con Herencia Simple

    + +

    Al intentar modelar este ejercicio con herencia simple, uno se encuentra con el problema de que no es posible separar en dos clases el comportamiento de Atacante y de Defensor, para luego hacer que Guerrero utilice ambos comportamientos. La herencia simple entonces no contribuye a una solución aceptable y se debe entonces buscar soluciones alternativas como composición que requieren una porción importante de glue code.

    + +

    Resolución con Mixins en Ruby

    + +

    Requerimiento descansar

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/kotest-testeo-unitario-avanzado.html b/wiki/articles/kotest-testeo-unitario-avanzado.html new file mode 100644 index 0000000000..e732005821 --- /dev/null +++ b/wiki/articles/kotest-testeo-unitario-avanzado.html @@ -0,0 +1,695 @@ + + + + + + + + + + + Testeo unitario avanzado + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Testeo unitario avanzado +

    +
    + + + +
    +

    Este artículo presenta algunas guías para desarrollar los casos de prueba, considerando que ya tienen una base de testeo unitario automatizado. Si estás buscando un apunte, te recomendamos el siguiente apunte de Testing.

    + +

    +
    +

    + +

    Por otra parte, aquí explicamos la mecánica utilizando Kotest como framework de testeo, si estás buscando una variante que siga los lineamientos de JUnit, podés ver esta página.

    + +

    Ejemplo

    + +

    Un sistema de seguros de automotor define en qué casos se puede pagar un siniestro:

    + +
      +
    • para los clientes normales, si no son morosos (la deuda debe ser 0)
    • +
    • para las flotas de autos, se soporta una deuda de hasta $ 10.000 si el cliente tiene más de 5 vehículos ó hasta $ 5.000 en caso contrario
    • +
    + +

    Definiendo los escenarios

    + +

    En base al ejemplo anterior, podemos considerar los siguientes escenarios:

    + +
      +
    • un cliente normal moroso: si debe $ 1 ó $ 50.000 no nos importa, porque está en la misma clase de equivalencia
    • +
    • una flota con menos de 5 autos (ó 5 autos) => serían “pocos” autos
    • +
    • una flota con más de 5 autos => serían “muchos” autos
    • +
    + +

    Elegimos cuántos autos en base al valor límite: como a partir de los seis autos se considera mucho y menos de 6 son “pocos” autos, 6 es el valor de una flota con muchos autos, 5 es el valor de una flota con pocos autos.

    + +

    Estructura de los tests

    + +

    La estructura que tienen los tests en base a los escenarios propuestos podría ser:

    + +
    +
    +
    +      dado un cliente normal
    +  ├── que es moroso: no puede cobrar un siniestro
    +  └── que no es moroso: puede cobrar un siniestro
    +dado un cliente de flota con muchos autos (6 autos)
    +  ├── si el cliente debe más de $ 10.000 no puede cobrar un siniestro
    +  └── si el cliente debe $ 10.000 o menos, puede cobrar un siniestro
    +dado un cliente de flota con pocos autos (5 autos)
    +  ├── si el cliente debe más de $ 5.000 no puede cobrar un siniestro
    +  └── si el cliente debe $ 5.000 o menos puede cobrar un siniestro
    +
    +    
    +
    +
    + +

    Definiendo las especificaciones de los tests

    + +

    Necesitamos

    + +
      +
    • un cliente normal
    • +
    • una flota de 6 autos
    • +
    • otra flota de 5 autos
    • +
    + +

    a los que podemos configurar diferentes grados de deuda. Podemos seguir algunas recomendaciones adicionales:

    + +

    Agrupar los escenarios en diferentes archivos

    + +

    Por el momento, no tenemos demasiados requerimientos. Entonces vamos a trabajar los tres escenarios desde el mismo archivo, al que llamaremos CobroSiniestroSpec.kt para explicitar el caso de uso que estamos testeando.

    + +

    +
    +

    + +

    A la hora de diseñar nuestros tests, hay dos ideas que están en tensión

    + +
      +
    • reutilizar nuestros escenarios, es decir, los objetos que estamos testeando
    • +
    • que en cada test quede claro qué objetos participan de esa prueba (lo que se llama SUT, System Under Test)
    • +
    + + +

    +
    +

    + +

    Por ejemplo, podríamos tener una flota con 6 autos y hacer tests para diferentes casos de uso: el cobro de un siniestro, el valor mensual de la cuota, el horario de atención, etc. El tema es que los tendremos en distintos archivos de test. La reutilización nos lleva a poner las cosas en un solo lugar, por ejemplo definiendo variables de instancia en una superclase común (o cualquier mecanismo que aumenta el alcance de la variable, volviéndola más global). Todo eso dificulta el entendimiento posterior del test, porque el código que se ejecuta previo a él está en varios lugares que además no son fáciles de rastrear. Más abajo veremos qué técnicas podemos utilizar para mantener nuestros tests simples.

    + + +


    +Cada uno de los escenarios se implementa con un describe diferente, entonces tendremos 3 describes:

    + +
      +
    • uno para clientes normales,
    • +
    • otro para una flota con pocos autos
    • +
    • y otro para una flota con muchos autos
    • +
    + +

    Es importante que no haya demasiados detalles de implementación en la descripción de los describes: “dada una flota con 5 autos” o “data una flota con 6 autos” provoca que cualquier cambio del negocio respecto a lo que son “muchos” o “pocos” autos necesite modificar esa descripción: es una duplicidad difícil de detectar.

    + +

    Intention revealing - parte 1

    + +

    Queremos expresar lo más claramente posible la intención del describe: qué clase de equivalencia está testeando. Por eso comenzamos escribiendo:

    + +
    +
    +
    +      describe("Tests Cobro Siniestro") {
    +		describe("Dado un cliente normal") {
    +			...
    +
    +		describe("Dada una flota con muchos autos") {
    +			...
    +
    +    
    +
    +
    + +

    Los describes agrupan los tests e incluso se pueden anidar, aunque por simplicidad solo vamos a utilizar un describe raíz para explicitar qué caso de uso estamos testeando. Una vez más recordamos: “muchos autos” es mejor que decir “6 autos”. En otras palabras, explicitar el caso de prueba y no el dato de prueba: 6 autos es un dato concreto, pero lo que representa es el caso de prueba de una flota con muchos autos.

    + +

    Expresividad en los tests

    + +

    Un primer approach

    + +

    Para crear nuestro fixture de una flota con muchos autos, los enunciados suelen traer ejemplos como: “Lidia Pereyra tiene una flota con 6 autos”. Es tentador escribir un test como el siguiente:

    + +
    +
    +
    +      describe("Lidia Pereyra") {
    +	val pereyra = Flota().apply {
    +		cantidadAutos = 6
    +	}
    +	it("no puede cobrar siniestro") {
    +		pereyra.generarDeuda(10001)
    +		pereyra.puedeCobrarSiniestro() shouldBe false
    +	}
    +	...
    +}
    +
    +    
    +
    +
    + +

    Pero ¿qué pasa si hay un error en el código de negocio? Supongamos esta implementación, donde la clase Cliente tiene la definición de la deuda como un entero:

    + +
    +
    +
    +      class Flota : Cliente() {
    +    var autos: Int = 0
    +
    +    override fun puedeCobrarSiniestro() =
    +        this.deuda <= maximoPermitido()
    +
    +    fun maximoPermitido() =
    +        if (autos <= 5) 5000 else 20000 // debería ser 10000 en lugar de 20000
    +
    +}
    +
    +    
    +
    +
    + +

    Cuando ejecutamos el test tenemos muy poca información relevante:

    + +

    + Kotest - nombre de variable no representativa +

    + +
      +
    • la variable pereyra no está revelando que es un cliente de flota con muchos autos
    • +
    • y tampoco está claro por qué no puede cobrar el siniestro el cliente.
    • +
    + +

    Al fallar la condición tenemos que bucear en el código y extraer este dato para determinar si el error está en el test o en el código de negocio.

    + +

    Una segunda oportunidad

    + +

    Vamos a mejorar la semántica del test, renombrando la variable pereyra por un nombre más representativo de la clase de equivalencia que estamos modelando y cambiando la descripción para el test:

    + +
    +
    +
    +      describe("Dada una flota con muchos autos") {
    +	val flotaConMuchosAutos = Flota()
    +	flotaConMuchosAutos.autos = 6
    +	it("si tiene mucha deuda no puede cobrar siniestro") {
    +		flotaConMuchosAutos.generarDeuda(10001)
    +		flotaConMuchosAutos.puedeCobrarSiniestro() shouldBe false
    +	}
    +
    +    
    +
    +
    + +

    Ahora al fallar el test sabemos más cosas:

    + +

    + mas expresividad en los tests +

    + +
      +
    • el test con su stack trace, pero también
    • +
    • qué es lo que estamos testeando, tratando de no entrar en detalles para no duplicar lo que dice el código
    • +
    + + +

    +
    +

    + +

    AAA Pattern

    + +

    Los tests suelen estructurarse según el patrón AAA: Arrange, Act y Assert.

    + +
    +
    +
    +      describe("Dada una flota con muchos autos") {
    +	// Arrange
    +	val flotaConMuchosAutos = crearFlota(6)
    +	it("si tiene mucha deuda no puede cobrar siniestro") {
    +		// Act
    +		flotaConMuchosAutos.generarDeuda(10001)
    +		// Assert
    +		flotaConMuchosAutos.puedeCobrarSiniestro() shouldBe false
    +	}
    +	it("si no tiene poca deuda puede cobrar siniestro") {
    +		// Act
    +		flotaConMuchosAutos.generarDeuda(10000)
    +		// Assert
    +		flotaConMuchosAutos.puedeCobrarSiniestro() shouldBe true
    +	}
    +}
    +
    +    
    +
    +
    + +

    Arrange

    + +

    En el Arrange: donde instanciamos los objetos a testear, con sus colaboradores: en el ejemplo son la flota y sus autos.

    + +

    Instanciar un objeto adecuado para el test puede involucrar varios pasos, en ese caso es conveniente definir métodos helpers que además puedan reutilizarse en diferentes contextos:

    + +
    +
    +
    +      fun crearFlota(cantidadAutos: Int) =
    +	Flota().apply {
    +		autos = cantidadAutos
    +	}
    +
    +...		
    +
    +describe("Dada una flota con muchos autos") {
    +	// Arrange
    +	val flotaConMuchosAutos = crearFlota(6)
    +
    +    
    +
    +
    + +

    En el ejemplo tenemos un método helper del test que permite crear un objeto Flota pasándole la cantidad de autos a crear. De esa manera la configuración de una flota ocurre en una sola línea y se puede incluir dentro del test mismo. El número 6 representa el valor límite para la flota, podríamos setearlo en base a una constante asociado a la clase Flota:

    + +
    +
    +
    +      // clase Flota
    +val LIMITE_MUCHOS_AUTOS = 5
    +
    +// el test
    +describe("Dada una flota con muchos autos") {
    +	// Arrange
    +	val flotaConMuchosAutos = crearFlota(LIMITE_MUCHOS_AUTOS + 1)
    +
    +    
    +
    +
    + +

    La única cuestión a tener en cuenta aquí es que está bueno que los tests tengan la mínima lógica posible, de manera de no estar repitiendo la misma lógica que ya tiene el negocio: la ventaja que tiene escribir crearFlota(6) es que si el límite de lo que se considera muchos autos cambia, el test falla y eso puede ser útil.

    + +
    +

    Una heurística posible sobre el setup del test es tratar de mantenerlo simple y de alto nivel, más cercano al lenguaje del dominio que con detalles de implementación. En el ejemplo de arriba se logra con mensajes que se encargan de instanciar objetos de dominio y que esconden la complejidad de conocer la colaboración entre la flota y sus autos). Una alternativa a tener métodos en el test puede ser crear un objeto específico que construya otro objeto, algo que dejaremos para más adelante.

    +
    + +

    +
    +

    + +

    Act

    + +

    Act: son las operaciones que tienen efecto. En el caso de la flota que tiene una deuda abultada, enviamos el mensaje que le genera la deuda. Hay tests que quizás no necesiten disparar acciones, y está bien que eso ocurra.

    + +

    Assert

    + +

    En el Assert indicamos qué esperamos que pase, generalmente asociado a las respuestas que da el envío de un mensaje al objeto testeado. Para esto utilizamos los matchers de Kotest.

    + +

    “One assert per test”

    + +

    Hay ciertas controversias respecto a si podemos tener varios asserts en el mismo test, ya que cuando el primer assert falla los siguientes no se siguen evaluando: esto en realidad depende del runner de los tests, podríamos eventualmente trabajar con un framework que continue buscando asserts y discrimine cuáles anduvieron y cuáles no (RSpec, framework de testeo para Ruby, hace ésto).

    + +

    En verdad, la heurística que nos interesa recomendar es: los tests deben fallar por exactamente un solo motivo, esto relaja esa restricción. Lo importante no es tener un solo assert, sino que todos los asserts estén relacionados con la misma funcionalidad. Dejamos un ejemplo concreto:

    + +
    +
    +
    +      describe("Dado un parser de patentes de autos") {
    +	it("se obtiene correctamente la parte numérica de una patente vieja") {
    +		val lista = PatenteParser("ABC257").parsearNumeros()
    +		lista.size shouldBe 3
    +		lista[0] shouldBe 2
    +		lista[1] shouldBe 5
    +		lista[2] shouldBe 7
    +	}
    +}
    +
    +    
    +
    +
    + +

    El lector puede profundizar con estos artículos:

    + + + +

    TL;DR

    + +

    Este es el resumen de buenas prácticas a la hora de definir tus tests:

    + +
      +
    • armá los escenarios que definen las clases de equivalencia de los tests
    • +
    • escribí la descripción de los describes y los tests explicando qué estamos testeando. El cómo lo terminás de ver en el código, evitá duplicidades entre el texto que explica y el código escrito
    • +
    • separá los describes por requerimientos / casos de uso y los tests por escenarios donde quede claro la clase de equivalencia (cliente común, flota, etc.)
    • +
    • los nombres de las variables deben reflejar la clase de equivalencia que están resolviendo, y no casos particulares que no revelan la intención de lo que estamos modelando (sí flotaConPocosAutos, no flotinha o miFlota)
    • +
    • los tests se suelen estructurar utilizando las tres A: Arrange (el setup que conviene mantenerlo simple), Act (operaciones con efecto cuando corresponde) y Assert (las aserciones que deben testear el mismo concepto en cada test)
    • +
    + +

    Links relacionados

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/kotlin-amigandonos-git.html b/wiki/articles/kotlin-amigandonos-git.html new file mode 100644 index 0000000000..d584f18427 --- /dev/null +++ b/wiki/articles/kotlin-amigandonos-git.html @@ -0,0 +1,496 @@ + + + + + + + + + + + Kotlin - control de versiones + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Kotlin - control de versiones +

    +
    + + + + + +
    +

    Los archivos a versionar en Git

    + +

    No todos los archivos deben subirse al repo. Como regla general no deberían subir archivos que se puedan generar a partir de otros, por ejemplo:

    + +
      +
    • los binarios que se generan a partir del código fuente de ustedes (el directorio build). Ocupan espacio en el repositorio y se corre el riesgo de estar trabajando con versiones desactualizadas.
    • +
    • archivos de configuración propios de IntelliJ (el directorio .idea), que se pueden armar en base al build.gradle.kts cuando se importa el proyecto en nuestra máquina la primera vez.
    • +
    • archivos que genera Gradle localmente (el directorio .gradle, distinto al gradle que es donde está el script ejecutable o wrapper). Si querés conocer más en profundidad la estructura de las carpetas que utiliza Gradle, te recomendamos esta página.
    • +
    + +

    Archivos a ignorar

    + +

    Debemos crear un archivo .gitignore (que en Wollok se los creó el propio entorno), en la carpeta raíz del proyecto, que debe tener al menos esta lista:

    + +
    +
    +
    +      HELP.md
    +.gradle
    +build/
    +!gradle/wrapper/gradle-wrapper.jar
    +!**/src/main/**/build/
    +!**/src/test/**/build/
    +
    +### STS ###
    +.apt_generated
    +.classpath
    +.factorypath
    +.project
    +.settings
    +.springBeans
    +.sts4-cache
    +bin/
    +!**/src/main/**/bin/
    +!**/src/test/**/bin/
    +
    +### IntelliJ IDEA ###
    +.idea
    +*.iws
    +*.iml
    +*.ipr
    +out/
    +!**/src/main/**/out/
    +!**/src/test/**/out/
    +
    +### NetBeans ###
    +/nbproject/private/
    +/nbbuild/
    +/dist/
    +/nbdist/
    +/.nb-gradle/
    +
    +### VS Code ###
    +.vscode/
    +
    +    
    +
    +
    + +

    Git por consola o Git con una herramienta visual?

    + +

    Da lo mismo, elegí la herramienta que mejor te resulte. El plugin de IntelliJ tiene un buen soporte para Git, aun así hay otras opciones (tenés los links en la página), lo importante es cómo te organizás con tus compañeres.

    + +

    Recomendaciones para trabajar con mi grupo

    + +

    Un día en la vida de una persona que desarrolla (si van a trabajar en una rama sola)

    + +
      +
    • Cuando empiezo el día primero sincronizo el repositorio para ver los cambios que no tengo en el código. Si no hay cambios, simplemente corro los tests y empiezo a codear como un campeón. Si no… +
        +
      • Acepto los cambios entrantes y en caso de ser necesario resuelvo conflictos
      • +
      • Corro los tests y veo que todo anda sobre ruedas
      • +
      • Vuelvo a sincronizar y veo que ya no quedan ni conflictos ni cambios sin aceptar
      • +
      • Subo mis cambios al repositorio remoto para que mis compañeros lo vean
      • +
      +
    • +
    • Ahora sí, a programo, programo, programo… y cuando termino, corro los tests
    • +
    • Y vuelvo a sincronizar contra el repositorio remoto
    • +
    + +

    En resumen:

    + +
      +
    • No pasa un día de trabajo sin hacer un commit y push al repositorio remoto. Esto implica planificar mi trabajo para que pueda subir algo al repositorio sin que rompa todo: hay que partir un cambio grande en pequeños pasos (iterativo, incremental).
    • +
    • Nunca deberían subir nuevos fuentes al repositorio sin explicar brevemente qué cambiaron. Si los mensajes son descriptivos (y “fix”, “asdsadsa” o “arreglo una cosita” definitivamente no lo son) rápidamente puedo detectar qué modificaron mis compañeros con sólo leer lo que escribieron en los commits. Una buena descripción me ayuda también a entender qué es lo que se modificó y por qué razón, especialmente útil a la hora de solucionar un conflicto o entender por qué se rompieron los tests.
    • +
    • El que rompe los tests paga las facturas.
    • +
    + +

    ¿Y si cada uno trabaja en una rama separada?

    + +
      +
    • “mejor, no voy a tener conflictos”: eso no es cierto. Cada vez que integres tu código en el branch principal se pueden romper tests o funcionalidades
    • +
    • no puede pasar más de 3 días sin abrir el PR (Pull Request), dejar pasar el tiempo hace que integrar tu código sea un proceso largo y tedioso
    • +
    • un TP no se puede entregar en 5 ramas distintas, tiene que haber una sola fuente de verdad y es la rama principal del repositorio remoto
    • +
    • tener integración continua es fundamental si queremos trabajar con ramas
    • +
    + +

    Metodología para trabajar en grupo

    + +
      +
    • los tests tienen que estar en verde siempre
    • +
    • los tests son de todos y todos somos responsables por mantenerlos
    • +
    • si encontramos un bug y no había un test que lo probaba agregamos uno
    • +
    • los tests son rápidos de correr (no pueden tardar 10 minutos)
    • +
    + + + +

    Links útiles

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/kotlin-bajar-un-proyecto-gradle-de-un-repositorio-git.html b/wiki/articles/kotlin-bajar-un-proyecto-gradle-de-un-repositorio-git.html new file mode 100644 index 0000000000..f377d9ab2a --- /dev/null +++ b/wiki/articles/kotlin-bajar-un-proyecto-gradle-de-un-repositorio-git.html @@ -0,0 +1,510 @@ + + + + + + + + + + + Bajar un proyecto Kotlin - Gradle de un repositorio git + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Bajar un proyecto Kotlin - Gradle de un repositorio git +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Descripción

    + +

    Este artículo asume la presencia de un entorno de trabajo Kotlin. En caso de que todavía no tengas instaladas esas herramientas, te recomendamos leer estas instrucciones.

    + +

    También se asume la preexistencia de un proyecto construido con Gradle y publicado en un repositorio Git, si lo que se desea es crear el proyecto en lugar de descargarlo, aquí están las instrucciones para la creación de un proyecto y su posterior publicación en el repositorio.

    + +

    El proceso tiene los siguientes pasos, que se detallan a continuación:

    + +

    + Git +

    + +
      +
    • Clonar el proyecto desde el repositorio remoto y alojarlo en nuestro espacio de trabajo local.
    • +
    • Hacer el build del proyecto Kotlin en IntelliJ tomando como base las definiciones de Gradle.
    • +
    + +

    Descarga (clone)

    + +

    El checkout se puede hacer

    + +
      +
    • desde el IntelliJ
    • +
    • o por consola
    • +
    + +

    A continuación explicaremos ambos pasos por separado.

    + +

    Por línea de comando

    + +

    Paso 1: clonación

    + +

    Para esto debemos

    + +
      +
    • ubicarnos en el directorio de trabajo
    • +
    • saber la URL del repositorio en el que se publicó el proyecto
    • +
    + + + +
    +
    +
    +      $ cd ~/workspace/materia # el directorio principal donde estén tus proyectos
    +$ git clone https://github.com/uqbar-project/eg-microprocesador-kotlin
    +
    +    
    +
    +
    + +

    En el directorio local se bajan los recursos del proyecto, incluyendo un directorio .git donde está la información. De ser necesario debemos cambiar la rama o branch de trabajo, por ejemplo al branch dev:

    + +
    +
    +
    +      $ git checkout dev
    +
    +    
    +
    +
    + +

    Paso 2: Importación del proyecto en IntelliJ

    + +

    Para importar un proyecto en IntelliJ una vez descargado

    + +
      +
    • si tenés un proyecto abierto, desde el menú principal: “File” > “Open…”
    • +
    • si no hay ningún proyecto abierto, el botón “Open”
    • +
    + +

    Nos puede aparecer una ventana de diálogo para que confiemos en el proyecto:

    + +

    + IntelliJ confiar en el proyecto +

    + +

    Aceptamos seleccionando la opción “Trust project” y entonces se importará el proyecto, al detectar que está hecho en Gradle se utilizará el archivo correspondiente para hacer el build. Te recomendamos que actives el check para que IntelliJ confíe en todos los proyectos que te descargás en la carpeta raíz de la materia.

    + +

    + IntelliJ build del proyecto +

    + +

    ¡Y ya podemos comenzar a trabajar!

    + + + +

    Descarga desde IntelliJ

    + +

    Integración de tu usuario de github (solo la primera vez)

    + +

    En caso de utilizar directamente el plugin de IntelliJ, te recomendamos integrar tu usuario de Github de la siguiente manera

    + +
      +
    • si tenés un proyecto abierto, desde el menú principal: “Git” > “Clone…”
    • +
    • si no hay ningún proyecto abierto, el botón “Get from VCS”
    • +
    + +

    Aparece esta ventana de diálogo, seleccionamos Github:

    + +

    + Github - selección en IntelliJ +

    + +
    + +

    Se abre una ventana de un navegador donde nos pide autorización para acceder a nuestra cuenta de github:

    + +

    + Github - autorización +

    + + + +
    + +

    Confirmamos qué cuenta de Github es la que vamos a integrar

    + +

    + Github - selección de la cuenta 1 +

    + +

    y presionamos el botón “Authorize JetBrains”:

    + +

    + Github - selección de la cuenta 2 +

    + + +
    + +

    Ingresamos la contraseña

    + +

    + Github - password +

    + + +
    + +

    (si activaste la autenticación en 2 pasos o 2FA es probable que tengas que ingresar tu token también).

    + +

    Una vez finalizado este paso ya podemos cerrar el navegador y volver a IntelliJ:

    + +

    + Github - cerrar navegador +

    + + + +

    Clonar un proyecto en IntelliJ

    + +

    Una vez que tengamos asociado el usuario el proceso es muy sencillo, porque tendremos acceso a todos los repositorios

    + +

    + IntelliJ clonar proyecto +

    + +

    Aquí podemos hacer una búsqueda y nos aparecerán todos los repositorios a los que tenemos acceso. Por último, solo debemos seleccionar el directorio donde vamos a bajar localmente nuestro proyecto para trabajar con el IDE y presionar el botón “Clone”. Nos puede aparecer una ventana de diálogo para que confiemos en el proyecto:

    + +

    + IntelliJ confiar en el proyecto +

    + +

    Aceptamos seleccionando la opción “Trust project” y entonces se importará el proyecto, al detectar que está hecho en Gradle se utilizará el archivo correspondiente para hacer el build. Te recomendamos que actives el check para que IntelliJ confíe en todos los proyectos que te descargás en la carpeta raíz de la materia.

    + +

    + IntelliJ build del proyecto +

    + +

    Si necesitamos movernos a otra rama, eso se puede hacer mediante la opción “Git” > “Branches” y seleccionando la rama que quieras + Checkout. También tenés la opción de hacer click sobre la rama que se muestra en la parte inferior del IDE:

    + +

    + IntelliJ cambiar la rama de Git +

    + +

    ¡Y ya podemos comenzar a trabajar!

    + + + +

    Links útiles

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/kotlin-ci.html b/wiki/articles/kotlin-ci.html new file mode 100644 index 0000000000..ceabdc3718 --- /dev/null +++ b/wiki/articles/kotlin-ci.html @@ -0,0 +1,507 @@ + + + + + + + + + + + Integración continua para materias con Kotlin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Integración continua para materias con Kotlin +

    +
    + + + + + +
    +

    Integración continua (CI)

    + +

    Definición

    + +

    La integración continua busca automatizar los cambios en el código que escriben varias personas en un proyecto de software. De esa manera

    + +
      +
    • facilita la experiencia de descargarse un proyecto y hacerlo funcionar localmente en nuestras máquinas
    • +
    • permite la detección temprana de errores, cuando es más fácil resolverlos.
    • +
    + +

    Qué necesitamos para implementarla en nuestro proyecto

    + +

    Para poder implementar la integración continua, necesitamos

    + +
      +
    • la comunicación entre las personas que desarrollan en el proyecto (es importante que se hablen entre ustedes)
    • +
    • un servidor de integración continua: Github Actions, CircleCI, Jenkins, etc.
    • +
    • configurar nuestro proyecto contra ese servidor: eso puede involucrar uno o más archivos
    • +
    • una herramienta de versionado: git, Mercurial, etc.
    • +
    • y sobre todo, una buena calidad de tests automatizados
    • +
    + +

    Estrategia propuesta para proyectos con Kotlin

    + +

    A continuación vamos a describir los pasos necesarios para que tu proyecto Kotlin tenga integración continua

    + +

    Servidor de integración continua

    + +

    El servidor de integración continua será el que provee Github, y tiene las ventajas de estar integrado a tu repositorio y no tener que hacer nada para activarlo. Podés navegarlo en la solapa Actions:

    + +


    +

    + +

    + GH Actions - repo +

    + + + +

    Configuración del CI en el proyecto

    + +

    Copiate este archivo en la siguiente estructura que hay que crear

    + +
    +
    +
    +      <directorio raíz>
    +└── .github
    +    └── workflows
    +        └── build.yml
    +
    +    
    +
    +
    + +

    Qué pasa entonces

    + +

    A partir de aquí, cada vez que:

    + +
      +
    • Hagas un push en las branches “main” o “master”
    • +
    • Crees un PR que quiera mergear a “main” o “master”
    • +
    • Hagas un push en las branches asociadas a uno de esos PR (mientras se encuentre abierto).
    • +
    + +

    En esas situaciones, Github Actions como servidor de integración continua hará lo siguiente de forma automática:

    + +
      +
    • clonará tu repositorio
    • +
    • lo compilará (build) en Kotlin mediante el script de Gradle
    • +
    • ejecutará los tests
    • +
    • en caso de error, mandará un mail avisando que el build falló (por el momento solo al autor del commit/PR) +
        +
      • si anduvo ok, por defecto no recibirás ninguna notificación
      • +
      +
    • +
    • si es un push directo, actualizará la badge de cobertura de JaCoCo en .github/badges/jacoco.svg
    • +
    • sí, en cambio, es un evento relacionado con un Pull Request no actualizará la badge, pero comentará en dicho PR con la cobertura actual luego de aplicar los cambios sugeridos.
    • +
    • Finalmente, subirá a la descripción de esta instancia del action un “artefacto” con un reporte de cobertura generado por JaCoCo en HTML. +
        +
      • Los artefactos son archivos que github permite almacenar, junto a logs, junto a un intento de build durante un periodo determinado de tiempo (actualmente un máximo de 90 días, tras lo cual son eliminados)
      • +
      +
    • +
    + +

    Todo esto es muy útil, ya que al automatizarlo no tendremos que acordarnos de hacerlo. Queda además registrado si cada commit pasa o no, lo cual nos ayuda a encontrar donde se ubica el código donde se originó el error.

    + +

    Agregando el Badge de Build al README

    + +

    El badge es un indicador visual de cómo resultó el último build, que ubicaremos en el archivo README. Para eso,

    + +
      +
    • ingresamos a nuestro repositorio, solapa Actions,
    • +
    • elegimos cualquiera de los builds
    • +
    • luego a la derecha hacemos click sobre el botón que tiene los tres puntos: ...
    • +
    • en el menú contextual elegimos la opción “Create Status Badge”, elegimos la rama que queremos y
    • +
    • presionamos el botón de copia.
    • +
    + +


    +

    + +

    + Kotlin CI - Crear status badge +

    + + +

    +
    +

    + +
      +
    • luego vamos al editor, pegamos el texto en el README y pusheamos al repositorio.
    • +
    + +

    Links útiles

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/kotlin-creacion-proyecto.html b/wiki/articles/kotlin-creacion-proyecto.html new file mode 100644 index 0000000000..171a1a811a --- /dev/null +++ b/wiki/articles/kotlin-creacion-proyecto.html @@ -0,0 +1,582 @@ + + + + + + + + + + + Kotlin - Cómo generar un proyecto desde cero + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Kotlin - Cómo generar un proyecto desde cero +

    +
    + + + + + +
    +

    Para realizar las prácticas, vas a crear un proyecto desde cero. Como ahora hay muchas más opciones, te dejamos una guía simple de cómo iniciarte.

    + +

    Crear proyecto Kotlin

    + +

    Desde IntelliJ tenemos dos opciones:

    + +
      +
    • sin ningún proyecto abierto, nos aparece un botón New project
    • +
    • o bien si tenemos un proyecto abierto, tenemos que abrir el menú File > New > Project...
    • +
    + +

    Eso abre la siguiente ventana de diálogo:

    + +

    + Creación de un nuevo proyecto en Kotlin +

    + +
      +
    • El nombre del proyecto no debe contener espacios ni caracteres especiales (IntelliJ te va a avisar)
    • +
    • Todos los ejemplos que vas a descargar de la materia, así como los proyectos en los que vas a trabajar, se basan en la tecnología Gradle. Asegurate que tengas seleccionada la opción Gradle en Build System y Kotlin para la opción Gradle DSL.
    • +
    • Revisamos que la opción en Project JDK por defecto sea la JDK 21, en caso contrario debemos ir a configurar la versión de Java
    • +
    • Te recomendamos que el group id sea ar.edu.zzzz.xxx donde zzzz sea la universidad y xxx sea la materia que estás cursando. Por ejemplo ar.edu.unsam.algo2 para la materia Algoritmos 2 de UNSAM. Esta opción está disponible si expandís el grupo “Advanced settings”.
    • +
    • El nombre del artefacto (Artifact ID) es el nombre de tu proyecto
    • +
    + +

    Cuando finalizamos, se genera un proyecto con un archivo build.gradle.kts, que es fundamental para que IntelliJ lea esas definiciones para el proyecto en otra máquina y descargue las dependencias.

    + +

    Archivo de configuración de Gradle

    + +

    Te dejamos un archivo con las dependencias base para la cursada de Algoritmos 2 (UNSAM) del aǹo 2024: build.gradle.kts de ejemplo. Luego tendrás que

    + +
      +
    • renombrar el archivo a build.gradle.kts
    • +
    • copiarlo al directorio raíz de tu proyecto ya creado
    • +
    • revisar el groupId para ver si es el adecuado
    • +
    • revisar las dependencias para ver si es necesario agregar algún elemento más
    • +
    + +

    Una vez que actualicemos ese archivo, desde IntelliJ nos aparecerán dos íconos para indicarnos que debemos sincronizar las definiciones de Gradle con las de nuestro IDE:

    + +

    + IntelliJ te avisa para sincronizar tu proyecto con la definición del archivo de Gradle +

    + +

    Al hacer click automáticamente se actualizarán las dependencias. Este proceso es muy importante ya que de otra manera podremos experimentar problemas como imports que no funcionan, o métodos que no se pueden encontrar (por estar usando versiones diferentes a las que queremos realmente).

    + +

    Continuous integration

    + +

    Por el momento, lo que necesitás es únicamente copiar este archivo en la siguiente estructura que hay que crear

    + +
    +
    +
    +      <directorio raíz>
    +└── .github
    +    └── workflows
    +        └── build.yml
    +
    +    
    +
    +
    + +

    Para más información podés consultar la página de integración continua para proyectos en Kotlin.

    + +

    Primeros pasos

    + +

    Vamos a crear nuestra primera clase Perro. Es importante notar que tendremos dos carpetas donde ubicaremos los fuentes:

    + +
      +
    • src/main/kotlin: donde irán las clases
    • +
    • src/test/kotlin: donde irán los tests
    • +
    + +

    Por eso, nos ubicamos en src/main/kotlin y con un botón derecho, seleccionaremos New > Kotlin Class/File.

    + +

    + Creando una nueva clase Kotlin en IntelliJ +

    + +

    Shortcuts de IntelliJ

    + +

    A continuación te dejamos algunas recomendaciones para que tu estadía en IntelliJ + Kotlin sea más feliz:

    + +
      +
    • “Cómo era para…?” Lo mejor es preguntarle al propio IDE, presionando dos veces Shift + Shift. Desde esa ventana de diálogo podés buscar cualquier palabra clave, como “New”, “Save”, “Run”, “Select”.
    • +
    + +

    + Presionando Shift dos veces tenés acceso al menú contextual para buscar cualquier opción +

    + + + +
    + +
      +
    • Presionar dos veces Ctrl + Ctrl te permite ejecutar cualquier comando válido desde el componente donde estés ubicado.
    • +
    + +

    + Presionando Ctrl dos veces tenés acceso al menú contextual para ejecutar test, programas, etc. +

    + + + +
    + +
      +
    • Alt + Enter activa sugerencias tanto para errores como para cosas que se pueden mejorar (warnings).
    • +
    + +

    + Presionando Alt + Enter sobre un error o warning, el IDE nos ofrece diferentes formas de resolverlos +

    + +

    Presionando la tecla F2 te podés mover al siguiente lugar del archivo donde hay un error o warning:

    + +

    + Moviéndose a través de errores y warnings mediante F2 +

    + + + +
    + +
      +
    • Nunca nos olvidemos de que nuestro código tiene que ser entendible para el resto de la humanidad y lo mejor es pedirle al IDE que lo haga mediante Ctrl + Alt + L o bien con Ctrl + Alt + Shift + L (te abre una ventana de diálogo con más opciones).
    • +
    + +

    + Formateando un archivo Kotlin +

    + +

    Tip: si estás trabajando en una distribución de Linux que utiliza KDE, el shortcut Ctrl + Alt + L es tomado por el sistema como la acción para bloquear la pantalla. Para desactivarlo seguí estas instrucciones.

    + +

    La configuración base se puede definir mediante File > Settings y luego: Editor > Code Style > Kotlin, aunque te recomendamos que dejes los valores por defecto, así como recomendamos que todas las personas tengan la misma configuración.

    + + +
    + +

    Por último, dos muy buenas opciones para seleccionar elementos son

    + +
      +
    • Ctrl + Alt + Shift + J: selecciona todas las ocurrencias de un elemento (para renombrarlo existe otro shortcut, Shift + F6)
    • +
    • Alt + J: permite ir seleccionando elementos similares uno por uno.
    • +
    + +

    + Seleccionando elementos dentro de un archivo +

    + + +
    + +

    Otros comandos útiles:

    + +
      +
    • Ctrl + D: duplica una línea
    • +
    • Ctrl + Y: elimina una línea
    • +
    + +

    Si estás trabajando con Mac los shortcuts son diferentes, en ese caso o bien para más información podés ver este artículo.

    + +

    Packages para agrupar código común

    + +
      +
    • Utilización de packages (paquetes). Es una buena práctica agrupar las clases afines en paquetes para organizar semánticamente el código. No hay una guía firme a seguir con respecto a cómo organizar nuestros archivos, ya que suele depender del contexto en el cual estamos trabajando, pero a medida que veas nuestros ejemplos y vayas haciendo las prácticas notarás que hay clases que se pueden agrupar en contextos similares. Te dejamos un ejemplo
    • +
    + +
    +
    +
    +      proyecto
    +   ├── home
    +   ├── registration
    +   │   ├── Profile.kt
    +   │   └── User.kt
    +   └── settings
    +       ├── CustomPrivacy.kt
    +       ├── DefaultPrivacy.kt
    +       ├── Privacy.kt
    +       └── Setting.kt
    +
    +    
    +
    +
    + +

    De esta manera, logramos mayor granularidad en la organización de nuestras clases. +___

    + +

    Links útiles

    + + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/kotlin-guia-rapida.html b/wiki/articles/kotlin-guia-rapida.html new file mode 100644 index 0000000000..92215a1ef4 --- /dev/null +++ b/wiki/articles/kotlin-guia-rapida.html @@ -0,0 +1,1750 @@ + + + + + + + + + + + Guia rapida de Kotlin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Guia rapida de Kotlin +

    +
    + + + + + +
    +

    La siguiente es una guía de syntactic sugars de Kotlin, algunos de los cuales trabajan conceptos más profundos que veremos a lo largo de la materia.

    + +

    Definición de una clase

    + +

    Una clase necesita un nombre, atributos a los cuales referencia y métodos, definidos mediante el prefijo fun.

    + +
    +
    +
    +      val ENERGIA_MINIMA = 10
    +
    +class Ave {
    +    var energia = 0
    +    fun volar() { energia = energia - 10 }
    +    fun comer(cuanto: Int) { energia = energia + (cuanto * 2) }
    +    fun esFeliz() = energia > ENERGIA_MINIMA
    +    fun resetearEnergia() { energia = 0 }
    +}
    +
    +    
    +
    +
    + +

    Reglas generales para la clase

    + +
      +
    • podemos escribir múltiples clases en un archivo Kotlin
    • +
    • la definición de la clase se encierra entre llaves
    • +
    + +

    Atributos

    + +
      +
    • la variable ENERGIA_MINIMA se define como una constante y es referenciable dentro de cualquier clase que esté dentro de ese archivo. Otra variante es definir atributos asociados a una clase específica (ver companion object), suele usarse como constantes o valores que difícilmente cambien.
    • +
    • la variable energia es una variable de instancia porque cada objeto Ave tiene su propio valor.
    • +
    • las variables tienen un tipo que se infiere en base al valor: en el caso de la energia es un número (Int) porque se asocia al valor 0 aunque podemos explicitarla nosotros de la siguiente manera:
    • +
    + +
    +
    +
    +      var energia: Int = 0
    +// la variable energia 
    +//    tiene el tipo Int y el valor por defecto 0
    +
    +    
    +
    +
    + +
      +
    • Kotlin automáticamente define getters y setters para la variable energia (no es necesario hacer nada, mientras no especifiquemos la visibilidad del atributo a privada, de la siguiente manera: private var energia = 0)
    • +
    • La manera de invocar al getter es: objeto.atributo y la manera de invocar al setter es objeto.atributo = valor:
    • +
    + +
    +
    +
    +      pepita.energia = 100    // <-- equivale a pepita.setEnergia(100)
    +pepita.energia          // <-- equivale a pepita.getEnergia()
    +
    +    
    +
    +
    + +

    ¡Ojo! si bien parece que estamos accediendo diréctamente a la variable de instancia, no es así. Kotlin simplemente traduce esa sintaxis a la anterior. Es decir que en ambos casos estamos igualmente llamando al getter y al setter. Pueden probar definiendo la variable energia como privada y el IDE mostrará un mensaje de error “Cannot access ‘energia’: it is private in ‘Ave’”.

    + +

    Métodos

    + +
      +
    • respecto a los métodos, algunos producen efecto (volar y comer) y otros simplemente devuelven un valor (esFeliz).
    • +
    • en el caso de los métodos con efecto, se delimitan con llaves. Por defecto los métodos que no devuelven nada no tienen ninguna anotación de tipo, se dice que son void o Unit.
    • +
    + +
    +
    +
    +      fun volar() { energia = energia - 10 }
    +
    +    
    +
    +
    + +
      +
    • los métodos que solo devuelven valores y tienen una sola línea se definen con el símbolo =:
    • +
    + +
    +
    +
    +      fun esFeliz() = energia > ENERGIA_MINIMA
    +
    +    
    +
    +
    + +
      +
    • también es posible definir un método que devuelve un valor mediante las llaves, definiendo una anotación de tipo para el método:
    • +
    + +
    +
    +
    +      fun esFeliz(): Boolean { 
    +    return energia > ENERGIA_MINIMA
    +}
    +
    +    
    +
    +
    + +

    En este caso el tipo de retorno del método es Boolean. Si el método tiene varias líneas es necesario utilizar este formato en lugar del =.

    + +

    Referencias variables y valores

    + +

    En Kotlin, al igual que muchos otros lenguajes, se diferencian las referencias como

    + +
      +
    • Variables: son referencias que pueden inicializarse apuntando a un objeto, y luego reasignarse a otro:
    • +
    + +
    +
    +
    +      var unString = "Pepito"
    +unString = "Otro String"
    +
    +    
    +
    +
    + +
      +
    • Constantes: son referencias que nacen apuntando a un valor y no pueden ser modificadas para apuntar a otro objeto. Serían como “constantes”.
    • +
    + +
    +
    +
    +      val constante = "Constante"
    +constante = "Otro"  // <----- NO COMPILA !
    +
    +    
    +
    +
    + +

    ¡Ojo! no confundir el hecho de que no se pueda modificar la “referencia” de la mutabilidad/inmutabilidad del objeto al que apunta. Puedo tener un “val” apuntando a un elemento que sí mute.

    + +
    +
    +
    +      val perro = Perro()
    +perro.nombre("Juan")
    +perro = Perro()        // <----- NO COMPILA: no puedo modificar la referencia
    +perro.nombre("Carlos") // <---- SI COMPILA y puedo mutar la referencia nombre de perro
    +
    +    
    +
    +
    + +

    Cuándo debería usar val y cuándo var

    + +

    Por defecto definí tus variables como val, a menos de que necesites modificar las referencias. Por ejemplo: la edad de una persona debería poder modificarse, en cuanto al nombre puede ser que no necesites modificarlo o sí, eso dependerá de las reglas de negocio. El motivo principal es acotar el efecto en nuestros programas, mientras menor sea el efecto, más fácil es controlar nuestro software, y más fácil será testearlo.

    + +

    Companion object

    + +

    Kotlin provee la posibilidad de definir un objeto companion dentro de una clase, que es global para todas sus instancias:

    + +
    +
    +
    +      class Ave {
    +    companion object {
    +        var ENERGIA_MINIMA = 100
    +        fun subirEnergiaMinima(cuanto: Int) { ENERGIA_MINIMA += cuanto }
    +        fun crear() = Ave()
    +    }
    +    var energia = 0
    +    fun esFeliz() = energia > ENERGIA_MINIMA
    +    ...
    +
    +    
    +
    +
    + +
      +
    • en lugar de definir la referencia ENERGIA_MINIMA como constante por fuera de la clase, la asociamos al companion object
    • +
    • para manipular la energía mínima (como por ejemplo para subirla o bajarla en base a un valor), debemos hacerlo también dentro del companion
    • +
    • y también ofrecemos un método para crear un Ave, que por el momento solamente hace Ave(), pero el mecanismo de instanciación podría tornarse más complejo y el companion object es adecuado para tal fin.
    • +
    + +

    Todo lo que definimos en el companion object es accesible para atributos y métodos de instancia (como por ejemplo el método esFeliz). Desde otra clase, podemos invocar a la función que crea un ave de la siguiente manera:

    + +
    +
    +
    +      val ave = Ave.crear()
    +
    +    
    +
    +
    + +

    Objetos singleton

    + +

    Kotlin provee la capacidad de definir objetos:

    + +
    +
    +
    +      object Pepita {
    +    var energia = 100
    +    fun volar(minutos: Int) {
    +        energia -= minutos * 2 + 10
    +    }
    +    fun comer(gramos: Int) {
    +        energia += gramos * 4
    +    }
    +}
    +
    +fun main() {
    +    Pepita.energia = 150
    +    Pepita.volar(5)
    +    Pepita.comer(2)
    +    System.out.println("La energia de pepita es ${Pepita.energia}")  // "La energia de pepita es 88"
    +}
    +
    +    
    +
    +
    + +

    Pepita es una instancia que se puede acceder globalmente, representa una implementación thread safe del Singleton que es más trabajosa de implementar en Java (podés investigar más en este artículo). Si trabajaste en Wollok (o Scala) el concepto es exactamente similar, solo que el nombre debe comenzar con mayúscula.

    + +

    Tipos de datos

    + +

    Strings

    + +

    Un string se encierra entre dobles comillas, o bien podemos aprovechar para escribir un texto largo con triples comillas dobles (lo que nos permite incluso utilizar enters). Podemos interpolar referencias de Kotlin mediante $ o bien utilizar código ejecutable usando ${zzz} donde zzz es código Kotlin.

    + +
    +
    +
    +      class Cliente {
    +    var nombre = "Juan" // string simple
    +
    +    fun saludo() = "Hola $nombre" // string simple interpolando una referencia
    +    
    +    // string con múltiples líneas interpolando código Kotlin
    +    fun saludoFormal() =
    +        """
    +        Bienvenido, ${nombre.trim()} a nuestra aplicación.
    +        En breve nos contactaremos con ud.
    +        """
    +}
    +
    +    
    +
    +
    + +

    Números

    + +

    Existen muchos tipos de datos diferentes para números:

    + +
      +
    • Int: es un número entero que admite negativos pero sin decimales
    • +
    • Double, Float: son números reales que admiten decimales pero con errores en las operaciones, es por ello que no debemos usarlo para operaciones sensibles (como transacciones bancarias o que requieran cálculos exactos). ¿Por qué? Por este código que podés probar en este REPL
    • +
    + +
    +
    +
    +      fun main() {
    +    val a: Double = 0.02
    +    val b: Double = 0.03
    +    val c: Double = b - a
    +    System.out.println(c)  // 0.009999999999999998
    +}
    +
    +    
    +
    +
    + +
      +
    • BigDecimal: es el tipo de dato que conviene utilizar ya que no produce errores de redondeo (permite trabajar con una cantidad exacta de decimales y truncarlos o redondearlos en caso de ser necesario)
    • +
    + +
    +
    +
    +      import java.math.BigDecimal
    +
    +fun main() {
    +    val a: BigDecimal = BigDecimal("0.02")
    +    val b: BigDecimal = BigDecimal("0.03")
    +    val c: BigDecimal = b - a
    +    System.out.println(c)    // 0.01
    +}
    +
    +    
    +
    +
    + +

    Tanto Int, como Double como BigDecimal representan objetos a los que podés enviarle mensajes:

    + +
    +
    +
    +      fun main() {
    +    val numero: Double = 10.0
    +    System.out.println(numero.inc())   // 11.0
    +    System.out.println(numero.rem(3))  // 1.0
    +}
    +
    +    
    +
    +
    + +

    Para más información pueden ver esta página.

    + +

    Colecciones mutables e inmutables

    + +

    En Kotlin, todas las colecciones vienen en dos “sabores”: mutables e inmutables. Las primeras soportan modificar sus elementos (agregar, quitar, actualizar), mientras que las segundas solo permiten acceder a sus elementos. Queda a criterio de quien programa cuál utilizar en cada caso, prefiriendo desde este espacio las inmutables (porque algo que no se puede modificar es menos propenso a errores).

    + +

    Existen literales para definir listas, conjuntos y mapas (dictionaries):

    + +
    +
    +
    +      fun main() {
    +    // Lista inmutable
    +    val myList = listOf("Hello", "World")
    +    myList.size
    +    // ERROR, no puedo agregar un elemento a una lista inmutable
    +    // └ myList.add("Goodbye")
    +    
    +    // Lista mutable
    +    val myMutableList = mutableListOf("Hello", "World")
    +    myMutableList.add("Goodbye")
    +    System.out.println("${myMutableList[1]}")  // "World"
    +
    +    // Set inmutable
    +    val mySet = setOf("Hello", "World")
    +    // ERROR, no puedo agregar un elemento a un set inmutable
    +    // └ mySet.add("Goodbye")
    +
    +    // Set mutable
    +    val myMutableSet = mutableSetOf("Hello", "World")
    +    myMutableSet.add("Goodbye")
    +    myMutableSet.add("Hello")  // no tiene efecto porque ya hay un elemento "Hello"
    +    System.out.println("${myMutableSet.size}")  // 3
    +
    +    // Mapa/Diccionario inmutable
    +    val myMap = mapOf("a" to 1 , "b" to 2)
    +    // ERROR, no puedo agregar un elemento a un set inmutable
    +    // └ myMap.set("c", 3)
    +    
    +    val myMutableMap = mutableMapOf("a" to 1 , "b" to 2)
    +    myMutableMap.set("c", 3)
    +    System.out.println("${myMutableMap.size}")  // 3
    +}
    +
    +    
    +
    +
    + +

    Recordemos que

    + +
      +
    • listas: respetan el orden en el que se agregan (como una fila) y admiten duplicados.
    • +
    • conjuntos: no tienen orden y tampoco admiten duplicados. Dos objetos son iguales en base a la definición de equals() y hashCode().
    • +
    • mapas: son un conjunto de pares clave/valor. Se acceden por clave.
    • +
    + +
    +

    Ojo 👀: no hay que mezclar las ideas de val y var con la (in)mutabilidad de las colecciones. Por ejemplo, una colección inmutable podría estar referenciada con var, mientras que una mutable podría ser val.

    +
    + +

    Para más información recomendamos leer

    + + + +

    Rangos con arrays

    + +

    Es posible generar un rango de números:

    + +
    +
    +
    +      // Array de enteros con valores [0, 0, 0, 0, 0]
    +val arrZeros = IntArray(5)
    +
    +// Array de enteros de tamaño 5 con valores [42, 42, 42, 42, 42]
    +val arrConstants = IntArray(5) { 42 }
    +
    +// Podemos utilizar una lambda para inicializar un array: [0, 1, 2, 3, 4]
    +var arrLambda = IntArray(5) { it }
    +// ... o [1, 2, 3, 4, 5]
    +var arrLambda = IntArray(5) { it + 1 }
    +
    +    
    +
    +
    + +

    Más abajo explicamos definición de bloques o lambdas.

    + +

    Inferencia de tipos

    + +

    Kotlin cuenta con inferencia de tipos, lo que permite

    + +
      +
    • que exista chequeo de tipos
    • +
    • pero que muchas veces no sea necesario definir los tipos de las expresiones
    • +
    + +

    Vemos un ejemplo en vivo, mostrando cómo cambia la solapa “Structure” (disponible mediante Alt+ 7) cuando modificamos el código:

    + +

    + Kotlin Type Inference +

    + +

    Volviendo a la inferencia de tipos, es fundamental poder contar con un lenguaje que tenga chequeo de tipos para detectar errores en forma temprana pero que no me obligue a definir los tipos todo el tiempo. La definición de tipos es obligatoria cuando la definición pueda resultar ambigua para Kotlin, por ejemplo cuando definas un método que retorna un valor pero no lo anotes en la definición:

    + +
    +
    +
    +      fun resetearEnergia() {
    +    energia = 0
    +    return true   // ERROR: la definición del método conflictúa con este return
    +}
    +
    +    
    +
    +
    + +

    En ese caso el IDE te mostrará un error y lo podés solucionar fácilmente indicando el tipo del valor a retornar (o bien eliminando la instrucción return):

    + +

    + Kotlin Fix method return +

    + +

    Instanciación y constructores

    + +

    Instanciación por defecto

    + +

    Para instanciar un objeto, Kotlin no utiliza la palabra new, simplemente se invoca mediante el nombre de la clase y paréntesis:

    + +
    +
    +
    +      class Entrenador {
    +    val ave = Ave()
    +
    +    
    +
    +
    + +

    Definiendo constructores

    + +

    Adicionalmente, podemos definir parámetros en la construcción de una clase (lo que en otros lenguajes se conoce como constructor):

    + +
    +
    +
    +      class Ave(var energia: Int = 0) {
    +    ...
    +}
    +
    +    
    +
    +
    + +

    El valor por defecto indica que podemos crear un ave sin pasar parámetros, en cuyo caso el valor de su energía será 0:

    + +
    +
    +
    +      val pepita = Ave() // un ave con energia = 0
    +
    +    
    +
    +
    + +

    Pero también podemos pasar un valor:

    + +
    +
    +
    +      val pepita = Ave(energia = 150) // un ave con energia = 150
    +
    +    
    +
    +
    + +

    Si en cambio no definimos un valor por defecto para energia

    + +
    +
    +
    +      class Ave(var energia: Int) {
    +    ...
    +
    +    
    +
    +
    + +

    es obligatorio pasarle un valor para energía:

    + +
    +
    +
    +      val ave = Ave()              // ERROR: No value passed for parameter 'energia'
    +val ave = Ave(energia = 200) // OK
    +
    +    
    +
    +
    + +

    Constructores secundarios

    + +

    Por lo general solo es necesario definir un constructor por defecto, pero en caso de que lo necesites te dejamos este artículo que explica cómo escribir constructores secundarios.

    + +

    Herencia y redefinición de métodos

    + +

    A continuación vemos cómo definir Golondrina como subclase de Ave.

    + +

    + image +

    + +
    +
    +
    +      open class Ave() {
    +    ...
    +    open fun esFeliz() = energia < ENERGIA_MINIMA
    +}
    +
    +
    +class Golondrina : Ave() {
    +    override fun esFeliz() = true
    +}
    +
    +    
    +
    +
    + +

    Aquí vemos que

    + +
      +
    • Golondrina hereda de Ave, indicado mediante el símbolo :
    • +
    • Golondrina debe llamar al constructor de Ave, que al no tener parámetros se indica por el momento con paréntesis vacíos: class Golondrina : Ave()
    • +
    • Golondrina redefine el comportamiento de esFeliz, lo pisa, y esto requiere la palabra clave override, de lo contrario el IDE mostrará un mensaje de error
    • +
    • Para que una clase pueda subclasificarse Kotlin obliga a utilizar la palabra clave open. Una segunda variante es que la clase sea abstracta en cuyo caso automáticamente es abierta.
    • +
    • La misma operatoria debe seguir un método: debe marcarse con la palabra clave open (como en el caso esFeliz) para poder redefinirse en las subclases, a menos de que el método sea abstracto. Esto es un poco burocrático y extraño para el objetivo general que suele tener Kotlin, pero por el momento es así.
    • +
    + +

    Torcaza: This y super

    + +

    Si queremos definir una clase Torcaza que redefina el comportamiento de volar pero que además delegue el comportamiento en la superclase, debemos utilizar la palabra clave super junto con el mensaje a enviar:

    + +
    +
    +
    +      class Torcaza : Ave() {
    +    var vecesQueVolo = 0
    +    override fun volar() {
    +        super.volar()
    +        vecesQueVolo++
    +    } 
    +}
    +
    +    
    +
    +
    + +

    Como regla general solo deben utilizar super cuando no puedan utilizar this, como en este caso: de lo contrario entrarían en loop infinito si invocaran a this.volar().

    + +

    Constructores delegado

    + +

    Si la clase Ave se definiera de la siguiente manera:

    + +
    +
    +
    +      open class Ave(var energia: Int = 0) {
    +
    +    
    +
    +
    + +

    eso no produciría ningún cambio en las definiciones de Golondrina y Torcaza ya que en cada invocación tomaría el valor por defecto de energía:

    + +
    +
    +
    +      class Torcaza : Ave() { // considera energia = 0
    +
    +    
    +
    +
    + +

    Ahora bien, si la definición del constructor en Ave no tuviera valor por defecto:

    + +
    +
    +
    +      open class Ave(var energia: Int) {
    +
    +    
    +
    +
    + +

    Entonces es necesario redefinir el constructor por defecto para Golondrina y Torcaza y pasarle ese valor al constructor de Ave. Esto se hace de la siguiente manera:

    + +
    +
    +
    +      class Golondrina(energia: Int) : Ave(energia) {
    +
    +    
    +
    +
    + +

    Si bien esto puede convertirse en algo tedioso, veremos que el IDE nos simplifica bastante esta tarea, utilizando Alt + Enter para aceptar la sugerencia:

    + +

    + Kotlin - Delegación de constructores +

    + +

    Clases y métodos abstractos

    + +

    Podemos definir a Ave como clase abstracta, esto producirá que no podamos instanciar objetos Ave. Una clase abstracta puede definir solo la interfaz de un método, lo que se conoce como método abstracto. Veamos el siguiente ejemplo:

    + +

    + image +

    + +

    En el ejemplo:

    + +
      +
    • primero definimos Ave como abstracta
    • +
    • eso provoca que el compilador tire un error cuando queremos instanciar un Ave en la clase Ornitologo
    • +
    • lo corregimos instanciando una Golondrina
    • +
    • luego, queremos definir un método abstracto: esFeliz. Para ello reemplazamos la definición por una cáscara que solo dice que esFeliz debe devolver un booleano. Dado que no hay código Kotlin nos fuerza a definir el tipo de retorno del método (y de sus parámetros) porque no puede inferirlo.
    • +
    • todos los métodos abstractos deben estar implementados en las subclases: el compilador nos avisa que falta la definición de esFeliz() en Torcaza. Con un botón derecho “Implement members” pegamos la definición copiada.
    • +
    + +

    y finalmente todo compila.

    + +

    Te dejamos el código completo:

    + +
    +
    +
    +      val ENERGIA_MINIMA = 10
    +
    +abstract class Ave(var energia: Int) {
    +    open fun volar() { energia = energia - 10 }
    +    fun comer(cuanto: Int) { energia = energia + (cuanto * 2) }
    +    abstract fun esFeliz(): Boolean
    +    fun resetearEnergia() { energia = 0 }
    +}
    +
    +class Golondrina(energia: Int) : Ave(energia) {
    +    override fun esFeliz() = true
    +}
    +
    +class Torcaza(energia: Int) : Ave(energia) {
    +    var vecesQueVolo = 0
    +    override fun volar() {
    +        super.volar()
    +        vecesQueVolo++
    +    }
    +
    +    override fun esFeliz() = energia < ENERGIA_MINIMA
    +}
    +
    +class Ornitologo {
    +    fun trabajar() {
    +        val ave = Golondrina(energia = 100)
    +        ave.comer(2)
    +        ave.volar()
    +    }
    +}
    +
    +    
    +
    +
    + +

    Interfaces

    + +

    Las interfaces son un mecanismo que permite definir un contrato, provisto por una serie de métodos que pueden o no estar definidos. Por ejemplo, veamos la interfaz Flying que expresa el contrato para cualquier elemento que sepa volar:

    + +
    +
    +
    +      interface Flying {
    +    fun isHappy(): Boolean
    +    fun fly()
    +}
    +
    +    
    +
    +
    + +

    Esto implica que cualquier definición que implemente la interfaz Flying debe poder responder a esos dos mensajes: isHappy() y fly(). Por ejemplo, la clase Bird, donde el símbolo : sirve tanto para marcar herencia como implementación:

    + +
    +
    +
    +      interface Flying {
    +    fun fly()
    +    fun isHappy(): Boolean
    +}
    +
    +// clase Bird implementa Flying
    +class Bird(var energy: Int = 100) : Flying {
    +    fun eat(howMuch: Int) { energy = energy + (howMuch * 2) }
    +    fun resetEnergy() { energy = 0 }
    +    override fun fly() { energy = energy - 10 }
    +    override fun isHappy() = energy > MIN_ENERGY
    +}
    +
    +    
    +
    +
    + +

    Cada método implementado debe anotarse con el prefijo override para indicar que está implementando los métodos que le pide su interfaz.

    + +

    ¿Por qué Flying no se define como clase abstracta? Podríamos, pero mientras que una clase solo tiene una superclase puede implementar varias interfaces a la vez. Supongamos que ahora definimos la interfaz Living para representar seres vivos:

    + +
    +
    +
    +      interface Living {
    +    var energy: Int
    +    fun eat(howMuch: Int)
    +}
    +
    +    
    +
    +
    + +

    Living define un atributo sin ningún valor concreto, ya que no puede definir un estado, a diferencia de la clase abstracta. Ahora Bird puede implementar ambas interfaces, para lo cual tiene que indicar que va a redefinir el atributo energy y todos los métodos abstractos requeridos por las interfaces Flying y Living:

    + +
    +
    +
    +      // clase Bird implementa las interfaces Flying y Living
    +class Bird(override var energy: Int = 100) : Flying, Living {
    +    override fun eat(howMuch: Int) { energy = energy + (howMuch * 2) }
    +    fun resetEnergy() { energy = 0 }
    +    override fun fly() { energy = energy - 10 }
    +    override fun isHappy() = energy > MIN_ENERGY
    +}
    +
    +    
    +
    +
    + +

    Por último, las interfaces permiten definir implementaciones para los métodos, como podemos ver en este ejemplo completo:

    + +
    +
    +
    +      val MIN_ENERGY = 100
    +
    +interface Flying {
    +    fun fly()
    +    fun isHappy(): Boolean
    +    fun canFly() = !isHappy()
    +}
    +
    +interface Living {
    +    var energy: Int
    +    fun eat(howMuch: Int) { energy = energy + (howMuch * 2) }
    +    fun resetEnergy() { energy = 0 }
    +}
    +
    +class Bird(override var energy: Int = 100) : Flying, Living {
    +    override fun fly() { energy = energy - 10 }
    +    override fun isHappy() = energy > MIN_ENERGY
    +}
    +
    +    
    +
    +
    + +

    Aquí vemos que cuando le preguntemos a un pájaro si puede volar, la definición la tomará de la implementación de Flying. Por otra parte cuando le pidamos a un pájaro que coma, lo hará en base a la definición de la interfaz Living. De todas maneras hay que estar seguro de que vamos a reutilizar en más de un lugar cada una de nuestras definiciones para no caer en el sobrediseño.

    + +
    +

    TIP: A la hora de reutilizar, una interface nos permite tomar definiciones de múltiples lugares aunque no permite definir un estado mientras que una superclase abstracta nos permite definir una sola vez nuestros atributos aunque solo podemos tener una superclase.

    +
    + +

    Bloques

    + +

    Un bloque permite definir una porción de código, también llamada expresión lambda:

    + +
    +
    +
    +      val cuadrado = { num: Double -> num.pow(2) }
    +cuadrado.invoke(5.0)  // 25
    +
    +    
    +
    +
    + +

    En este caso cuadrado es un bloque que recibe como parámetro un número con decimales y devuelve el cuadrado de dicho número. Si queremos definir el tipo de dato de cuadrado podemos:

    + +
    +
    +
    +      val cuadrado: (Double) -> Double = { num: Double -> num.pow(2) }
    +cuadrado.invoke(5.0)  // 25
    +
    +    
    +
    +
    + +

    En general un bloque en Kotlin tiene la siguiente sintaxis:

    + +
    +
    +
    +      { parametro: Tipo, parametro2: Tipo2 -> expresión a resolver }
    +
    +    
    +
    +
    + +

    De esta manera podemos enviar bloques como parámetros, algo muy útil para trabajar entre otras cosas con las colecciones (map, filter, fold, etc.)

    + +

    Variable implícita it

    + +

    Dentro de una expresión lambda, it es la variable implícita del primer parámetro, por lo tanto todas estas expresiones son equivalentes:

    + +
    +
    +
    +      System.out.println(alumnos.filter { alumno: Alumno -> alumno.estudioso() })
    +System.out.println(alumnos.filter { it.estudioso() })
    +
    +    
    +
    +
    + +

    Para más información pueden consultar la página oficial de lambdas de Kotlin.

    + +

    Manejo de nulls

    + +

    100 veces no debo

    + +

    Los valores nulos son siempre un dolor de cabeza, Kotlin es uno de los primeros lenguajes orientados a objetos que nace con una estrategia para mitigarlos. En principio una referencia definida como String o Int no acepta valores nulos.

    + +

    + Kotlin - String no acepta null +

    + +

    Ok, entonces podríamos pensar que una solución es sacar el null explícito, y si como dijo Iván Noble algunos errores son deliciosos, sin dudas uno es éste:

    + +

    + Kotlin - no permite dejar sin inicializar +

    + +

    Debemos inicializar la referencia, ¡exacto! porque de otra manera lo que pasa es que arrastramos un String que puede ser null por todo nuestro código, solo por no tomar la decisión de que ese valor nunca puede ser nulo.

    + +

    Lateinit

    + +

    Una variante para resolver el problema es definir el atributo como lateinit:

    + +
    +
    +
    +      class Persona {
    +    lateinit var nombre: String
    +    fun tieneNombreLargo() = nombre.length > 10
    +}
    +
    +    
    +
    +
    + +

    El efecto que provoca es que Kotlin confía en que nosotros vamos a definir siempre un valor para el nombre de cada persona antes de utilizarlo. Por ejemplo:

    + +
    +
    +
    +      fun main() {
    +    val pepe = Persona()
    +    pepe.nombre = "Pepe"
    +    System.out.println(pepe.tieneNombreLargo())  // false
    +}
    +
    +    
    +
    +
    + +

    Y no hay ningún inconveniente. ¿Qué pasa si en cambio probamos con esta variante?

    + +
    +
    +
    +      fun main() {
    +    val pepe = Persona()
    +    System.out.println(pepe.tieneNombreLargo())
    +}
    +
    +    
    +
    +
    + +

    Kotlin se va a quejar de que nosotros le dijimos “quedate tranquilo que yo me ocupo del nombre” y resultó que el nombre quedó sin inicializar:

    + +
    +
    +
    +      Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property nombre has not been initialized
    + at Persona.getNombre (File.kt:2) 
    + at Persona.tieneNombreLargo (File.kt:3) 
    + at FileKt.main (File.kt:8)
    +
    +    
    +
    +
    + +

    Más adelante, cuando trabajemos con algunos frameworks como Spring, veremos que el modificador lateinit nos va a ser de mucha utilidad. Mientras tanto, cuando nosotros controlamos la inicialización de las referencias para cada objeto, la mejor estrategia es definir un valor no-nulo por defecto:

    + +
    +
    +
    +      class Persona {
    +    var nombre: String = ""
    +    fun tieneNombreLargo() = nombre.length > 10
    +}
    +
    +    
    +
    +
    + +

    Valores que aceptan null

    + +

    Para aceptar valores null todos los tipos deben incorporar el sufijo ?, por ejemplo String?, Int?, etc.

    + +
    +
    +
    +      class Persona {
    +    var nombre: String? = null
    +    ...
    +
    +    
    +
    +
    + +

    El inconveniente es que para saber si una persona tiene nombre largo, tenemos que considerar ahora si tiene un nombre nulo:

    + +

    + Kotlin - Non null safe operation +

    + +

    Operador !!

    + +

    Una opción es utilizar el operador !! sobre nombre, que implica nuevamente confiar en que el nombre no va a ser nulo:

    + +
    +
    +
    +      fun tieneNombreLargo() = nombre!!.length > 10
    +
    +    
    +
    +
    + +

    Esto implica que anulamos la validación y nos puede pasar lo mismo que en otros lenguajes como Java: al enviar un mensaje a una referencia nula el programa explota en tiempo de ejecución.

    + +
    +
    +
    +      Exception in thread "main" java.lang.NullPointerException
    + at Persona.tieneNombreLargo (File.kt:3) 
    + at FileKt.main (File.kt:8) 
    + at FileKt.main (File.kt:-1) 
    +
    +    
    +
    +
    + +

    Elvis operator

    + +

    Parece un emoticón, pero ?: es un shortcut para utilizar un valor por defecto cuando una expresión pueda ser nula:

    + +
    +
    +
    +      fun tieneNombreLargo() = (nombre ?: "").length > 10
    +
    +    
    +
    +
    + +

    En este caso, si la referencia nombre no está inicializada, se toma en cuenta la segunda expresión (el string vacío).

    + +

    Null safe operator

    + +

    También podemos resolver envíos de mensajes a referencias que potencialmente podrían ser nulas:

    + +
    +
    +
    +      class Alumno(var nombre: String = "") {
    +    fun estudioso() = ...
    +    fun felicitar() { ... }
    +}
    +
    +fun main() {
    +    val alumnos = listOf(Alumno(nombre = "Valar"), Alumno(nombre = "Arya"))
    +    val estudioso = alumnos.find { it.estudioso() }
    +    System.out.println(estudioso?.nombre) // null
    +    estudioso?.felicitar()
    +}
    +
    +    
    +
    +
    + +

    Si estamos buscando información del primer alumne estudiose (o de algune) enviando el mensaje find a la colección puede pasar que la búsqueda no encuentre ningún elemento. En ese caso el operador ?. es equivalente a escribir:

    + +
    +
    +
    +      val estudioso = alumnos.find { it.estudioso() }
    +System.out.println(if (estudioso === null) null else estudioso.nombre) // null
    +if (estudioso !== null) {
    +    estudioso.felicitar()
    +}
    +
    +    
    +
    +
    + +

    pero como vemos es bastante menos tedioso de escribir. De todas maneras cuando sea posible es una buena práctica evitar la manipulación de tipos de datos con valores nulos, porque no siempre se puede resolver mágicamente con un ? cualquier operación:

    + +

    + Kotlin - null safe no válido +

    + +

    Entonces el consejo que te dejamos es solo dejar valores que acepten nulls cuando el negocio realmente lo necesite. Por ejemplo: si un perro puede tener dueño o no, entonces el atributo puede ser nullable.

    + +

    Comparar referencias

    + +

    Tenemos dos formas de comparar referencias en Kotlin:

    + +
      +
    • Igualdad referencial: definido por el operador ===. ref1 === ref2 si ambas referencias apuntan al mismo objeto. Esto lo determina la VM y no se puede cambiar.
    • +
    • Igualdad estructural: definido por el operador ==. ref1 == ref2 en base a la definición del método equals() en la clase a la que pertenece ref1.
    • +
    + +

    Tener especial atención a los strings, ya que dos strings con el mismo contenido pueden ser iguales pero no idénticos, dependiendo de las estrategias de optimización de la VM. Vemos un ejemplo ilustrativo:

    + +
    +
    +
    +      fun main() {
    +    val nombre = "Ernesto"
    +    val nombre2 = "Ernesto ".trim()
    +    System.out.println(nombre == nombre2)   // true, tienen el mismo contenido
    +    System.out.println(nombre === nombre2)  // false, no son el mismo objeto
    +}
    +
    +    
    +
    +
    + +
    +

    Tip: Siempre es conveniente utilizar ==, que además se puede redefinir en nuestras clases / objetos.

    +
    + +

    Features avanzados

    + +

    Extension methods

    + +

    Una de las herramientas más poderosas consiste en definir extension methods. Supongamos que un negocio tiene un horario de apertura y de cierre y queremos saber, dada una hora, si está abierto.

    + +
    +
    +
    +      class Negocio {
    +    var horarioApertura: Int = 9
    +    var horarioCierre: Int = 18
    +
    +    fun estaAbierto(horaActual: Int) =
    +        horaActual.between(horarioApertura, horarioCierre)
    +}
    +
    +    
    +
    +
    + +

    Por supuesto, no compila. No existe el método between asociado a los enteros. Pero podemos definir un extension method en cualquier archivo:

    + +
    +
    +
    +      fun Int.between(from: Int, to: Int) = this in from..to
    +
    +    
    +
    +
    + +

    Si definiste la extensión en otro paquete, lo importás como cualquier otra definición:

    + +
    +
    +
    +      package otroPackage
    +
    +import between
    +
    +class Negocio {
    +    ...
    +
    +    
    +
    +
    + +

    En resumen, un extension method permite que nosotros agreguemos comportamiento por afuera de la definición de una clase como si estuviéramos trabajando en ella, algo muy importante cuando la clase no podemos modificarla (como en el caso de Int, String), o bien cuando se está regenerando todo el tiempo (cuando tenemos un framework que genera código para nosotros), sin contar que además estamos respetando la idea de mensaje (y por consiguiente, la posibilidad de seguir trabajando con polimorfismo).

    + +

    Data classes

    + +

    Kotlin provee el concepto de Data class para definir clases que sirven para modelar valores (value objects):

    + +
    +
    +
    +      data class Point(val x: Int, val y: Int) {
    +    // ... definiciones adicionales ...
    +}
    +
    +fun main() {
    +    val punto = Point(2, 4)
    +    System.out.println(punto.x)               // 2
    +    System.out.println(punto)                 // Point(x=2, y=4)
    +    System.out.println(punto == Point(2, 4))  // true
    +}
    +
    +    
    +
    +
    + +

    Aquí vemos que el data class Point

    + +
      +
    • define un constructor con dos parámetros que a su vez definen las variables x e y
    • +
    • los getters para x e y existen automáticamente
    • +
    • como x e y son val esto hace que nuestro objeto Point sea inmutable, si sumamos dos puntos obtenemos un nuevo punto (como pasa al concatenar los strings “hola΅ y “mundo” donde se obtiene un nuevo string “holamundo” o al sumar 2 + 3 el resultado es un nuevo número 5)
    • +
    • si definimos x (o y) como var, Kotlin le agrega los setters correspondientes
    • +
    • el método toString de un data class que crea Kotlin es muy conveniente, permite mostrar tanto la clase como su estado interno (a comparación del toString por defecto que tiene Object que muestra solo el nombre de la clase y un número interno en formato hexadecimal)
    • +
    • y por último también redefine el método equals de manera de utilizar igualdad estructural: dos puntos son iguales si tienen la misma información, porque cuando modelamos value objects es frecuente crear objetos para representar ciertos datos y después se descartan
    • +
    + +
    +

    Tip: qué objetos son candidatos a modelarse con data class: un Mail, un domicilio, en general cuando estamos agrupando información que está junta pero que no es específica de un dominio, la identidad no es importante como pasa cuando definimos objetos cliente, producto, etc.

    +
    + +

    Operadores para procesar múltiples envíos de mensajes

    + +

    Otro syntactic sugar muy interesante de Kotlin es la posibilidad de enviar múltiples mensajes al mismo objeto, mediante varios operadores:

    + +
      +
    • apply
    • +
    • let
    • +
    • with
    • +
    • run
    • +
    • also
    • +
    + +
    +
    +
    +      val ventaNacional = Venta().apply {
    +    cantidadKilos = 12
    +    fechaVenta = LocalDate.now()
    +    parcela = parcela50
    +    comprador = CompradorNacional()
    +}
    +
    +    
    +
    +
    + +

    De esta manera, todos los mensajes se apuntan al objeto que resulta de evaluar la expresión Venta(), y simplifica el envío de mensajes:

    + +
    +
    +
    +      ventaNacional.cantidadKilos = 12
    +ventaNacional.fechaVenta = LocalDate.now()
    +ventaNacional....
    +
    +    
    +
    +
    + +

    Otras variantes

    + +

    Las scope functions let, also, run y with son similares pero tienen ligeras variaciones para lo que sea más conveniente en cada caso:

    + +

    Let

    + +

    El valor que le pasamos como parámetro se referencia como it y lo que devuelve es el resultado de toda la operación:

    + +
    +
    +
    +      Venta().let { it.cantidadKilos * it.parcela.tamanio } // devuelve un número
    +
    +    
    +
    +
    + +

    With

    + +

    El valor que le pasamos como parámetro se referencia como this y lo que devuelve es el resultado de toda la operación. También es útil para trabajar el ejemplo original de la creación de una venta diciendo “a este objeto enviale estos mensajes”:

    + +
    +
    +
    +      val ventaNacional = Venta()
    +with(ventaNacional) {
    +    cantidadKilos = 12
    +    fechaVenta = LocalDate.now()
    +    parcela = parcela50
    +    comprador = CompradorNacional()
    +}
    +
    +    
    +
    +
    + +

    Para más información (como las scope functions run y also) pueden ver este artículo

    + +

    Links relacionados

    + + + +

    Links útiles

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/kotlin-preparacion-de-un-entorno-de-desarrollo.html b/wiki/articles/kotlin-preparacion-de-un-entorno-de-desarrollo.html new file mode 100644 index 0000000000..2df8f08bd8 --- /dev/null +++ b/wiki/articles/kotlin-preparacion-de-un-entorno-de-desarrollo.html @@ -0,0 +1,546 @@ + + + + + + + + + + + Kotlin - Preparacion del entorno de desarrollo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Kotlin - Preparacion del entorno de desarrollo +

    +
    + + + + + +
    +

    + +

    + +

    Instalación base

    + +

    Git Bash (sólo para Windows)

    + +

    Para simplificar el uso de Git en entornos Windows, existe la herramienta Git Bash que podés descargar a partir de esta página, haciendo click en el link “Download”.

    + +

    Si estás en Mac o Linux, podés saltear este paso.

    + +

    JDK: Java Development Kit

    + +

    Primero instalaremos el compilador de Java.

    + +

    Ingresamos a una de las siguientes direcciones, y descargamos la JDK 21, que es la versión que manejamos desde 2024:

    + +
      +
    • (Recomendado) Adoptium Eclipse Temurin - JDK provisto por la Fundación Eclipse, y con apoyo activo al proyecto de parte de multiples compañías como Microsoft y RedHat (entre otras). El código se distribuye usando la licencia GPL con ciertas restricciones provista por Oracle.
    • +
    • Amazon Corretto - Otra variante de JDK distribuida (y con soporte a largo plazo) por parte de Amazon. Si bien se encuentra optimizada para sus sistemas de AWS (Amazon Web Services), es una alternativa que funciona sin inconvenientes en sistemas tradicionales, para los que ofrece descargas.
    • +
    + +

    Pasos de instalación

    + +

    Una vez descargado el binario en una carpeta (supongamos que es C:\jdk21), hay que configurar dos variables de entorno de tu sistema operativo:

    + +
      +
    • JAVA_HOME: tiene que apuntar a C:\jdk21)
    • +
    • PATH: hay que incorporarle C:\jdk21\bin (cuidando de no borrar lo que ya está)
    • +
    + +

    Te dejamos un video que explica cómo hacerlo para Windows (el procedimiento es similar para MacOS / Linux)

    + +

    Chequeos posteriores a la instalación

    + +
      +
    • Dentro de las variables de entorno de tu sistema operativo debe estar JAVA_HOME asignada. En Linux / Mac esto es env | grep JAVA_HOME, y en Windows SET JAVA_HOME. Si la variable no está seteada, eso significa que te salteaste un paso, lo mismo si la carpeta que muestra JAVA_HOME no es la que contiene la versión que vos descargaste. En ese caso volvé al punto anterior y seguí nuevamente las instrucciones para encontrar lo que está faltando.
    • +
    • En una ventana de línea de comandos, verificar la versión de java instalada con java -version, y el compilador mediante javac -version. En ambos casos mostrará la versión por defecto para tu máquina. Si no aparece la versión que descargaste, el sistema operativo asume por defecto otra instalación, que podría ser incluso de una JRE (ver más abajo). En ese caso, revisá el link del punto anterior para ver qué puede estar faltando y repetí los pasos.
    • +
    + +

    JDK sí, JRE no

    + +
    +

    IMPORTANTE: tenés que instalar una JDK, no una JRE (Java Runtime Environment) que solo te permite ejecutar programas Java ya compilados. Para saber si tenés una JDK, deberías ir al directorio de instalación y en la carpeta bin debe estar un programa llamado javac, que es el compilador de Java.

    +
    + +

    + image +

    + +

    Si no tenés ese programa, no vas a poder pasar tus objetos a código ejecutable en el entorno Kotlin: la solución es muy simple, descargá e instalá una JDK. Para más información te recomendamos esta página

    + +

    IntelliJ IDEA

    + +

    Nuestro entorno integrado de desarrollo (IDE) permite que en una misma herramienta editemos nuestro código fuente, compilemos, hagamos pruebas, y muchas cosas más. En Algoritmos 1 ya conociste otro IDE: Eclipse, modificado especialmente para soportar el lenguaje Wollok. Aquí utilizaremos IntelliJ IDEA que tiene muchas similitudes con Eclipse.

    + +

    Pasos de instalación

    + +

    Tenés que descargarlo desde esta página y te va a ofrecer dos opciones:

    + +
      +
    • Ultimate: es la versión que recomendamos, para obtener una licencia podés enviar una solicitud con tu cuenta de UNSAM (debe terminar en @unsam.edu.ar ya que de esa manera se comprueba el origen educativo de la cuenta) siguiendo los pasos que cuenta esta página.
    • +
    • Community: es la versión open-source que no tiene disponibles los plugins para Spring, herramienta que vemos en Algoritmos 3 y Programación con Herramientas Modernas.
    • +
    + +

    Chequeos de instalación

    + +

    Una vez que te descargaste el instalable, solo tenés que

    + +
      +
    • elegir la ruta donde va a quedar el ejecutable (podés dejar la que te ofrece el instalador)
    • +
    • chequear la opción para que te aparezca el link al ejecutable IntelliJ (64-bit launcher)
    • +
    • las otras opciones no son necesarias activarlas
    • +
    + +

    y finalmente presionar Next hasta terminar el asistente.

    + +

    Necesitarás definir un espacio de trabajo o workspace, que es la carpeta donde vas a ubicar todos tus proyectos. Por defecto ese directorio es ~/IdeaProjects donde ~ es tu carpeta personal (como C:\Users\fernando o /home/fernando).

    + +

    Configuraciones adicionales

    + +

    Por lo general no es necesario hacer nada más, solo en algunos casos en los que notes que funciona lento, podés configurar el tamaño de memoria de la Virtual Machine de Java mediante el menú Help > Custom VM Options. Esto abre un archivo de texto similar al siguiente

    + +
    +
    +
    +      -Xms128m
    +-Xmx2048m
    +-XX:ReservedCodeCacheSize=512m
    +-XX:+UseConcMarkSweepGC
    +-XX:SoftRefLRUPolicyMSPerMB=50
    +-XX:CICompilerCount=2
    +-XX:+HeapDumpOnOutOfMemoryError
    +-XX:-OmitStackTraceInFastThrow
    +-ea
    +-Dsun.io.useCanonCaches=false
    +-Djdk.http.auth.tunneling.disabledSchemes=""
    +-Djdk.attach.allowAttachSelf=true
    +-Djdk.module.illegalAccess.silent=true
    +-Dkotlinx.coroutines.debug=off
    +-Dsun.tools.attach.tmp.only=true
    +
    +    
    +
    +
    + +

    Los parámetros que tenés que revisar son:

    + +
      +
    • la memoria inicial con la que levanta IntelliJ: Xms
    • +
    • la memoria máxima que puede ser utilizada para IntelliJ, que corre en una Virtual Machine de Java propia: Xmx. Por defecto viene con 2GB y para las necesidades de la materia no deberías tener que subirlo, pero en todo caso charlalo con tu docente favorito. +
        +
      • Este parámetro específico puede alterarse más sencillamente mediante el menú Help > Change Memory Settings +image
      • +
      +
    • +
    + +

    Para más información podés chequear esta página.

    + +

    Plugin Kotest

    + +

    Solo necesitamos agregar un plugin para ejecutar los tests unitarios: Kotest. Para instalarlo podés ir a esta página y clickear el botón Install to IntelliJ xxx donde xxx es la versión más reciente que hayas instalado.

    + +

    Alternativamente se puede instalar abriendo el menú File > Settings, abriendo la sección “Plugins > Marketplace” y buscando “Kotest” allí.

    + +

    Plugins de temas (Themes)

    + +

    Si te interesa configurar un tema de tu interés, podés buscar plugins que contengan la palabra “Theme” en el Marketplace, como se describe en esta página. Luego podrás seleccionar el tema de tu preferencia.

    + +

    Inlays

    + +

    En versiones recientes puede ser que te aparezca un inlay que muestra información sobre los autores del código en el repositorio que estás trabajando, algo que puede resultar un poco molesto. Para deshabilitarlo, podés seguir los pasos que se explican a continuación: Settings -> Editor -> Inlay Hints -> Code vision y desactivar la opción Code author. Luego cerrá los archivos que tengas abierto y volvelos a abrir nuevamente.

    + +

    + inlay hints +

    + +

    Actualizaciones automáticas

    + +

    Una vez instalado IntelliJ, el sistema te avisa cuando hay actualizaciones. Nuestra recomendación es que esperes para instalarlo a que finalice el cuatrimestre a menos de que estés teniendo un problema serio para trabajar en tu entorno y sepas que la actualización lo resuelve.

    + + + +

    Links útiles

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/kotlin-principal.html b/wiki/articles/kotlin-principal.html new file mode 100644 index 0000000000..199b6bf21d --- /dev/null +++ b/wiki/articles/kotlin-principal.html @@ -0,0 +1,371 @@ + + + + + + + + + + + Kotlin - pagina principal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Kotlin - pagina principal +

    +
    + + + + + +
    +

    + +

    A continuación te vamos a dejar los pasos de instalación del entorno Kotlin para las materias Algoritmos 2, Algoritmos 3 y Programación con Herramientas Modernas. Seguí metódicamente los puntos y no saltees las verificaciones para asegurarte que en tu máquina tengas todas las herramientas necesarias para trabajar.

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/lambdas-en-java-8.html b/wiki/articles/lambdas-en-java-8.html new file mode 100644 index 0000000000..bae8720109 --- /dev/null +++ b/wiki/articles/lambdas-en-java-8.html @@ -0,0 +1,507 @@ + + + + + + + + + + + Lambdas en java 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Lambdas en java 8 +

    +
    + + + +
    +

    En la versión 8 del lenguaje Java se introduce una herramienta fundamental para cualquier lenguaje de programación orientado a objetos y que era una de sus principales falencias: las expresiones lambda, también conocidas como bloques de código o funciones anónimas.

    + +

    Con ellas podemos implementar fácilmente mensajes de alto nivel de abstracción, que reciben o devuelven bloques de código y se comportan de forma parecida a las funciones de orden superior que podemos encontrar en el Paradigma Funcional.

    + +

    Dado que el lenguaje Java existió mucho tiempo sin presentar Lambdas (a partir de utilizar Clases Anónimas), estas presentan características distintivas si las comparamos con los bloques de Ruby o Smalltalk, o las funciones anónimas de Scala o C#.

    + +

    Uso básico

    + +

    En una primera aproximación, una lambda es cualquier objeto que implementa algunas de las siguientes interfaces:

    + +
      +
    • Function: una función que toma un sólo argumento
    • +
    • Predicate: una función que toma un sólo argumento pero que devuelve exclusivamente booleanos
    • +
    • Consumer: una función que toma un sólo argumento y no devuelve nada, probablemente porque produce un efecto. Es decir, los Consumers normalmente NO son computaciones puras.
    • +
    • Para otras variantes, ver: http://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
    • +
    + +

    Si queremos recibirlas por parámetro, debemos simplemente tipar al parámetro de nuestro método con alguna de estas interfaces.

    + +

    Ejemplo:

    + +
    Persona primerPersonasQueCumple(Predicate<Persona> predicado) {
    +   for(Persona persona : personas)
    +      if (predicado.test(persona))
    +         return persona;
    +   throw new PersonaNoExisteException();
    +}
    +
    + +

    Para pasarlas por parámetro, la sintaxis es la siguiente:

    + +
    (TipoParametro parametro) -> cuerpo
    +
    + +

    que es análogo al siguiente bloque en Smalltalk (recordar que en Smalltalk las variables no se tipan explícitamente):

    + +
     [ :parametro | cuerpo  ]
    +
    + +

    Ejemplo:

    + +
    primerPersonaQueCumple((Persona p) -> p.esMayorDeEdad())
    +
    + +

    En muchos casos como el anterior tipo del parámetro puede ser obviado, cuando este puede ser inferido por el contexto:

    + +
    primerPersonaQueCumple(p -> p.esMayorDeEdad())
    +
    + +

    Referencias a métodos

    + +

    Si el cuerpo del método es el envío de un sólo mensaje (como en el ejemplo anterior), entonces podemos usar una MethodReference:

    + +
    primerPersonaQueCumple(Persona::esMayorDeEdad)
    +
    + +

    Interfaces de un sólo mensaje

    + +

    Por motivos de retrocompatibilidad, en realidad, cualquier interface que defina un sólo mensaje puede ser usada con la sintaxis de lambda. Ejemplo:

    + +
    interface ChequeadorDePersona {
    +   boolean chequear(Persona p);
    +}
    +
    + +
    Persona primerPersonasQueCumple(ChequeadorDePersona predicado) {
    +   for(Persona persona : personas) 
    +      if (predicado.chequear(persona))
    +         return persona;
    +   throw new PersonaNoExisteException();
    +}
    +
    + +

    Y se usa exactamente igual. De todas formas, si no pensamos darle alguna semántica particular a nuestro bloque de código, preferiremos usar normalente las interfaces estándar comentadas anteriormente.

    + +

    Colecciones en Java

    + +

    Una de las principales utilidades de las lambdas es el manejo de colecciones. Java 8 incorpora mensajes a sus colecciones para poder transformarlas usando mensajes análogos a las funciones de orden superior de Haskell: map, filter y reduce(fold), limit(take), entre otros: http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html

    + +

    La forma de trabajar siempre es la misma: cuando tengamos una colecciones, le enviaremos el mensaje stream() para obtener una secuencia potencialmente infinita (análoga a las listas de Haskell), al cual le podemos enviar mensajes para filtrar, mapear, etc. Cuando hayamos terminado, y si queremos reconvertir nuestro Stream a una colección (como una List, Set, o Collection), le enviaremos el mensaje collect, indicandole a que tipo de colección queremos convertirlo:

    + + + +

    Ejemplo:

    + +
    List<Persona> personas = Arrays.asList(jose, pedro, maria, anabela);
    +Set<Persona> nombresDeDocentesSinRepetidos = personas
    +    .stream()
    +    .filter( Persona::esDocente)
    +    .map(Persona::getNombre)
    +    .collect(toSet());
    +
    + +

    Lo cual es análogo al siguiente código Smalltalk:

    + +
     personas := { jose. pedro. maria. anabela }
    + nombresDeDocentesSinRepetidos := 
    +     ((personas select: [ :p | p esDocente ]) collect: [ :p | p nombre ] ) asSet
    +
    + +

    Ordenar

    + +

    El orden superior se puede aprovechar para ordenar colecciones en Java. Supongan que tienen:

    + +
    public class Foo {
    +   private String bar;
    +   private int baz;
    +   // y sus getters y constructor
    +}
    +
    + +

    Cuando quieran tener algo ordenado según un criterio, antes o después, necesitarán un Comparator: es un objeto que nos dice si un objeto es “menor” que otro (precede a otro, dirían en discreta). La buena noticia es que normalmente no tendrán que declarar una clase que implemente esta interfaz, sino que podrán definirlo usando una lambda. Por ejemplo, si quieren crear una priorirty queue que esté ordenada según bar, pueden hacer:

    + +
    PriorityQueue<Foo> foos = 
    +    new PriorityQueue<>((x, y) -> x.getBar().compareTo(y.getBar()));
    +
    + +

    En general ni siquiera es necesario hacer la comparación a mano. Si quieren ordenar por una propiedad (como en este caso) pueden utilizar Comparator.comparing:

    + +
    PriorityQueue<Foo> foos = 
    +    new PriorityQueue<>(Comparator.comparing(foo -> foo.getBar()));
    +
    + +

    o lo que es lo mismo:

    + +
    PriorityQueue<Foo> foos = 
    +    new PriorityQueue<>(Comparator.comparing(Foo::getBar));
    +
    + +

    Si tienen que ordenar por multiples propiedades, pueden utilizar el mensaje thenComparing. Ejemplo de creación de un TreeSet que ordene segun bar y luego segun baz:

    + +
    Set<Foo> foos = 
    +    new TreeSet<>(
    +        Comparator.comparing(Foo::getBar).thenComparing(Foo::getBaz)
    +    );
    +
    + +

    Finalmente, si tienen que ordenar al revés del orden de precedencia, pueden usar el mensaje reversed. Por ejemplo, acá se está obteniendo un stream ordenado por baz, de mayor a menor:

    + +
    Arrays.asList(new Foo("hola", 2), 
    +              new Foo("hello", 9))
    +        .stream()
    +        .sorted(Comparator.comparing(Foo::getBaz).reversed());
    +
    + +

    Para más información, miren la documentación de Comparator: http://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html

    + +

    Nombres alternativos

    + +

    A veces se referencia a las lambda de Java como closure. En términos generales esto no es correcto, dado que son ideas diferentes: una lambda es una función que no tiene nombre, mientras una closure o cierre o clausura es una función que puede acceder a las variables disponibles en el contexto en que se la declaró.

    + +

    Sin embargo en este lenguaje informalmente y en términos prácticos ambos conceptos son intercambiables, ya que todas las lambdas encierra su contexto, y el unico tipo de closure que se puede tener es con una lambda.

    + +

    Como prueba de esto, históricamente, los frameworks de Java llamaban a la interfaz a ser implementada con una clase anónima indistintamente como Closure, Function o Lambda.

    + +

    Más información

    + +

    Para más información consultar:

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/lectura-de-un-paper.html b/wiki/articles/lectura-de-un-paper.html new file mode 100644 index 0000000000..5fea0737b7 --- /dev/null +++ b/wiki/articles/lectura-de-un-paper.html @@ -0,0 +1,313 @@ + + + + + + + + + + + Lectura de un paper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Lectura de un paper +

    +
    + + + +
    +

    Un Paper puede leerse con distintos niveles de profundidad, según el interés que tengamos sobre el tema. Obviamente esto es una guía, no hace falta ser tajante al respecto:

    + +

    Profundidad 1

    + +

    Leemos el título y/o el abstract. A veces al leer el título ya sabemos si nos interesa o no el tema. A veces hace falta leer el abstract para saber si el contexto sobre el que se trabajó es aplicable a mi trabajo o no.

    + +

    Por ejemplo, si leo en el contexto que solucionó un problema X para lenguajes funcionales con chequeo estático de tipos, y yo busco soluciones para Smalltalk, probablemente no me sirva :).

    + +

    Profundidad 2

    + +

    Ok, leí el abstract y pareció bueno. Leemos la introducción, los problemas que se presentan, Related work y conclusiones. Con eso nos empapamos bastante en el tema sin entrar en detalles. Obviamente a partir de aca podemos decidir si nos interesa o no ver en detalle la solución que propone el tipo. En caso que nos interese, podemos pasar a la profundidad 3.

    + +

    Profundidad 3

    + +

    Leemos todo, incluída la solución, discusión… Ok, podemos saltearnos la implementación, je.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/lenguajes-del-paradigma-logico.html b/wiki/articles/lenguajes-del-paradigma-logico.html new file mode 100644 index 0000000000..2f476dd5e5 --- /dev/null +++ b/wiki/articles/lenguajes-del-paradigma-logico.html @@ -0,0 +1,358 @@ + + + + + + + + + + + Lenguajes del paradigma logico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Lenguajes del paradigma logico +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Icon

    + +

    Si bien es un lenguaje basado en procedimientos, su ejecución goal oriented posibilita un estilo de programación que guarda bastantes similitudes con el paradigma lógico. Además la posibilidad de contar con generators permite utilizar backtracking dentro de los procedimientos.

    + +

    Por otro lado tiene soporte para realizar aplicaciones con interfaces gráficas. También existe una versión denominada Jcon que permite un fácil integración con Java.

    + +

    La página principal del lenguaje Icon es: https://www2.cs.arizona.edu/icon/ pero la introducción más clara la encontré en: http://en.wikipedia.org/wiki/Icon_programming_language

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/lenguajes-especificos-de-dominio.html b/wiki/articles/lenguajes-especificos-de-dominio.html new file mode 100644 index 0000000000..7370b66d87 --- /dev/null +++ b/wiki/articles/lenguajes-especificos-de-dominio.html @@ -0,0 +1,337 @@ + + + + + + + + + + + Lenguajes especificos de dominio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Lenguajes especificos de dominio +

    +
    + + + +
    +

    Este artículo está en construcción, tenemos por ahora algunos puntos de referencia solamente:

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/lenguajes-para-centrales-nucleares.html b/wiki/articles/lenguajes-para-centrales-nucleares.html new file mode 100644 index 0000000000..9a06c22dc0 --- /dev/null +++ b/wiki/articles/lenguajes-para-centrales-nucleares.html @@ -0,0 +1,302 @@ + + + + + + + + + + + Lenguajes para centrales nucleares + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Lenguajes para centrales nucleares +

    +
    + + + +
    +
      +
    1. REDIRECCIÓN Robustez de los lenguajes
    2. +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/lenguajes.html b/wiki/articles/lenguajes.html new file mode 100644 index 0000000000..843e17fd9a --- /dev/null +++ b/wiki/articles/lenguajes.html @@ -0,0 +1,338 @@ + + + + + + + + + + + Lenguajes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Lenguajes +

    +
    + + + +
    +

    A continuación mencionamos algunos lenguajes que siguen las ideas del paradigma orientado a objetos, y les dejamos algunos links y ejemplos para los curiosos.

    + + + +

    Híbridos

    + +

    Algunos lenguajes si bien implementan ciertas ideas del paradigma de objetos, también implementan abstracciones de otros paradigmas. Algunos de ellos son:

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ley-de-demeter.html b/wiki/articles/ley-de-demeter.html new file mode 100644 index 0000000000..23a593b56f --- /dev/null +++ b/wiki/articles/ley-de-demeter.html @@ -0,0 +1,448 @@ + + + + + + + + + + + Ley de demeter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Ley de demeter +

    +
    + + + +
    +

    Usamos la “ley de demeter” siempre que es posible (que es la mayoría de las veces), pueden consultarla acá, un resumen:

    + +
      +
    • You can play with yourself.
    • +
    • You can play with your own toys (but you can’t take them apart),
    • +
    • You can play with toys that were given to you.
    • +
    • And you can play with toys you’ve made yourself.
    • +
    + +

    You can play with yourself

    + +

    Esto significa que podemos enviarnos mensajes a uno mismo:

    + +

    Wollok:

    + +
    object pepita {
    +    method graznar(){
    +        self.gastarEnergia()
    +    }
    +    // ...
    +}
    +
    + +

    (self soy yo mismo, me envío el mensaje gastarEnergia())

    + +

    You can play with your own toys (but you can’t take them apart)

    + +

    Esto significa que nuestros atributos están para mandarles mensajes:

    + +

    Wollok:

    + +
    object pepita {
    +    var ciudadActual = bsAs
    +    method estasContenta(){
    +        return ciudadActual.esGrande()
    +    }
    +    // ...
    +}
    +
    + +

    (ciudadActual es un atributo de pepita, al que se le envía el mensaje esGrande())

    + +

    Pero no está bueno meterme con su composición interna:

    + +
    object pepita {
    +    var ciudadActual = bsAs
    +    method estasContenta(){
    +        return ciudadActual.poblacion().size() > 50000 //esto es incorrecto
    +    }
    +    // ...
    +}
    +
    + +

    (es incorrecto hablar con los objetos que le pido a los objetos que le pido a los objetos…. Ya que eso es como “desarmar” a ciudadActual. Directamente debo pedirle lo que necesito, que es saber si es grande)

    + +

    You can play with toys that were given to you

    + +

    Esto significa que puedo hablar con los parámetros que me lleguen

    + +
    object pepita {
    +    method queresIrA(otraCiudad){
    +        return otraCiudad.esGrande()
    +    }
    +    // ...
    +}
    +
    + +

    (otraCiudad es un parámetro que me llega en este método, por eso ahora mismo puedo hablarle y mandarle el mensaje esGrande())

    + +

    And you can play with toys you’ve made yourself

    + +

    Esto significa que puedo hablar con los objetos que yo haya creado:

    + +
    object pepita {
    +    method anioActual{
    +        return new Date().year()
    +    }
    +    // ...
    +}
    +
    +

    (new Date() representa el día de hoy, que lo acabo de crear, y le mando el mensaje year())

    + +

    Resumen

    + +

    Puedo mandarles mensajes a self, a mis atributos, a lo que me llega por parámetro, y a los objetos que creé yo.

    + +

    Entonces, esto es incorrecto:

    + +
    object pepita {
    +    method queresIrA(){
    +        return otraCiudad.esGrande()
    +    }
    +    // ...
    +}
    +
    + +

    … porque ¿de dónde sacó la otraCiudad? No es un parámetro, no es un atributo….

    + +

    Nota sobre los WKOs

    + +

    Hay muchos lenguajes que ofrecen puntos de acceso globales a ciertos objetos, con quienes también se puede hablar.

    + +

    Por ejemplo, en Smalltalk puedo hablar con las clases, que son objetos globales:

    + +
    #Golondrina>>ciudadNatal
    +   ^ Ciudad getInstance: 'BuenosAires'
    +
    +

    (Hablo con Ciudad, que es una clase, y le digo getInstance:, lo que me da una ciudad bien conocida)

    + +

    Y en Wollok existen los WKOs (well known objects), que permiten hablarles directamente sin conocerlos:

    + +
    object pepita {
    +    method enQueKMNaciste() {
    +        return buenosAires.kilometro()
    +    }
    +    // ...
    +}
    +
    + +

    (puedo hablar con buenosAires, aunque no sea ni un parámetro ni un atributo, ya que es un WKO)

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/libreria-y-framework.html b/wiki/articles/libreria-y-framework.html new file mode 100644 index 0000000000..17a9655286 --- /dev/null +++ b/wiki/articles/libreria-y-framework.html @@ -0,0 +1,345 @@ + + + + + + + + + + + Libreria y framework + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Libreria y framework +

    +
    + + + +
    +

    Librería

    + +

    Una librería es un conjunto de funciones llamadas desde “afuera” por un cliente. Dentro del POO, esto es una clase que recibe un mensaje, lo ejecuta y devuelve luego el control al cliente. La instanciación de una librería es relativamente sencilla.

    + +

    + +

    Framework

    + +

    El framework representa una abstracción de diseño y tiene un comportamiento en sí mismo. No es solamente una clase, sino que es un conjunto de objetos que se relacionan para servir a un dominio específico.

    + +

    La integración con mi sistema se da de múltiples maneras

    + +
      +
    • a veces extiendo de una superclase propia del framework,
    • +
    • o defino un objeto que respeta el contrato que pide el framework,
    • +
    • o envío un mensaje a un objeto del framework
    • +
    + +

    pero es usual que el framework me pida luego cosas a mí, no tengo control sobre el flujo de envío de mensajes.

    + +

    La instanciación del framework no es tan sencilla, ya que requiere un conocimiento del mismo.

    + +

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/lista-de-proyectos.html b/wiki/articles/lista-de-proyectos.html new file mode 100644 index 0000000000..aca9dd984a --- /dev/null +++ b/wiki/articles/lista-de-proyectos.html @@ -0,0 +1,323 @@ + + + + + + + + + + + Lista de proyectos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Lista de proyectos +

    +
    + + + +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/listas-por-comprension.html b/wiki/articles/listas-por-comprension.html new file mode 100644 index 0000000000..c7ea4080f3 --- /dev/null +++ b/wiki/articles/listas-por-comprension.html @@ -0,0 +1,346 @@ + + + + + + + + + + + Listas por comprension + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Listas por comprension +

    +
    + + + +
    +

    Tal vez recuerden de matemática que se pueden definir conjuntos por extensión (por ejemplo {1,2,5,9}) o por comprensión ({X \ X Є Enteros ^ X > 3 ^ X < 15} ). La forma por extensión ya la vimos con en Haskell con las listas [1,2,5,9] y por comprensión podemos definirla mediante filtros y transformaciones (filter y map) sobre otra lista que sería el conjunto base.

    + +

    Las listas por comprensión en Haskell son un azúcar sintáctico que nos permite armar listas a partir de los elementos de otra luego de aplicar filtros y transformaciones, o sea, permiten escribir de una forma simple y elegante expresiones que podrían ser más complejas utilizando las funciones que ya conocemos para este fin.

    + +

    Veamos un ejemplo simple usando filter y map:

    + +

    nombresDeAlumnosQueAprobaron = map nombre . filter aprobo

    + +

    Esta función puede también escribirse con una lista por comprensión:

    + +

    nombresDeAlumnosQueAprobaron alumnos = [nombre alumno | alumno <- alumnos, aprobo alumno]

    + +

    Una diferencia que podemos notar entre ambas definiciones es la cantidad de parámetros a la izquierda del igual, en el segundo caso hay uno, mientras que en el primero no hay. ¿Por qué pasa eso?

    + +

    Eso pasa porque

    + +

    map nombre . filter aprobo

    + +

    es una función ya que es la composición de dos funciones.

    + +

    En cambio

    + +

    [nombre alumno | alumno <- alumnos, aprobo alumno]

    + +

    es una lista, esa es una diferencia importante y es un criterio que nos va a permitir saber cuándo nos conviene usar map y filter en lugar de listas por comprensión.

    + +

    Otra cosa que agregan las listas por comprensión es la posibilidad de hacer pattern matching quedando aún más expresivo:

    + +

    [nombre | (nombre, nota) <- alumnos, nota > 4]

    + +

    Otro ejemplo si tengo una lista de remeras de la forma:

    + +

    modelos = [("GoodIdeaBadIdea", "flex", 2, "negro"), ...]

    + +

    A partir de esa lista podemos construir otra usando listas por comprensión y pattern matching:

    + +

    [(nombre, color) | (nombre, _, cant, color) <- modelos, cant > 2]

    + +

    Aquí se puede ver la verdadera potencia de las listas por comprensión vs. map y filter, la posibilidad de utilizar el pattern matching.

    + +

    En resumen:

    + +
      +
    • Las listas por comprensión nos dan funcionalidades similares a las del map y filter, entonces es probable que en muchas situaciones se presenten como soluciones alternativas a un mismo problema.
    • +
    • Las listas por comprensión permiten aprovechar mejor el pattern matching, entonces en los casos donde pueda usar esa característica probablemente sea más piola usar listas por comprensión en lugar de map y filter.
    • +
    • Con listas por comprensión yo siempre defino una lista, mientras que combinando map y filter con aplicación parcial yo puedo definir funciones, eso los hace más aptos para la composición, por lo tanto en los casos en que yo necesite componer (o trabajar al nivel de función por cualquier otro motivo, puede resultar más adecuado usar map, filter, aplicación parcial, composición, etc.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/locro.html b/wiki/articles/locro.html new file mode 100644 index 0000000000..cc25b1c6a9 --- /dev/null +++ b/wiki/articles/locro.html @@ -0,0 +1,332 @@ + + + + + + + + + + + Locro + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Locro +

    +
    + + + +
    +

    Nuestra mega receta para 30 personas:

    + +

    Para el locro:

    + +
      +
    • 2kg Maiz Blanco
    • +
    • 1Kg de Porotos
    • +
    • 2kg de Rost beef
    • +
    • 2kg de Bondiola
    • +
    • 2kg de Pechito de cerdo y Patitas
    • +
    • 1kg de Panceta
    • +
    • 5 Chorizos colorados
    • +
    • 4kg de Zapallo
    • +
    + +

    Para la salsa:

    + +
      +
    • 3 Cebollas
    • +
    • Ají molido c/n
    • +
    • 1/2 kg Grasa
    • +
    • Comino c/n
    • +
    • Pimentón c/n
    • +
    + +

    Receta original 1

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/logico---trabajo-con-valores.html b/wiki/articles/logico---trabajo-con-valores.html new file mode 100644 index 0000000000..c3f4d4c9af --- /dev/null +++ b/wiki/articles/logico---trabajo-con-valores.html @@ -0,0 +1,395 @@ + + + + + + + + + + + Logico trabajo con valores + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Logico trabajo con valores +

    +
    + + + +
    +

    Cuándo se usa is

    + +

    Cuando tengo que hacer una operación aritmética, p.ej..

    + +

       ingresoTotal(Pers,IT):- ingresoPorSueldo(Pers,IS), ingresoPorRenta(Pers,IR), IT is IS+IR.

    + +

    en este caso, la cuenta es una suma, debo usar is.

    + +

    Si lo de la izquierda es un valor, o una variable ligada con un valor, entonces el is se verifica si el resultado de la cuenta es el valor. P.ej. si quiero saber si juan tiene exactamente el doble de ingreso que roque, puedo hacer esta consulta

    + +

       ?- ingresoTotal(juan,IngrJuan), ingresoTotal(roque,IngrRoque), IngrJuan is IngrRoque * 2.

    + +

    No está bien usar el is cuando lo de la derecha no es una cuenta. Más detalles a continuación.

    + +

    Si sé qué valor es, pongo el valor

    + +

    Si en un programa quiero representar “bart es hijo de homero”, ¿pongo?

    + +

      hijo(X,Y):- X=bart,Y=homero.

    + +

    o pongo

    + +

      hijo(bart,homero).

    + +

    Está claro que pongo lo segundo. ¿Por qué? Porque no quiero decir “X e Y son hijo y padre si a X le pasa tal cosa y a Y le pasa tal otra”, sino que ya sé quiénes son los que quiero relacionar, bart y homero.

    + +

    En todos (todos) los casos en los que ya sé el valor, lo correcto es poner el valor, no hace falta “pasar” por una variable (como sería la variable X para bart en el ejemplo de arriba). Algunos ejemplos menos obvios.

    + +
      +
    1. Estoy haciendo un programa que modela gustos en propiedades de la gente, donde a cada propiedad la modelo con un átomo que describe su dirección (p.ej. lavalle851). Tengo estas reglas
    2. +
    + +
      +
    • A los que viven en Belgrano le gustan los departamentos lujosos.
    • +
    • A Roque le gustan los departamentos chiquitos.
    • +
    • A los que viven en Boedo les gusta el departamento de Corrientes 3804.
    • +
    + + + +

    En la primera regla sólo me dan condiciones sobre persona y depto:

    + +

      gusta(Pers,Depto):- vive(Pers,belgrano), esLujoso(Depto).

    + +

    En la segunda, no me están hablando de una persona cualquiera, me están hablando de Roque. Entonces el primer argumento no necesita ser una variable

    + +

      gusta(roque,Depto):- esChiquito(Depto).

    + +

    Para la tercera, del que me están hablando específicamente es del depto, de la persona me dan condiciones. Entonces

    + +

      gusta(Pers,corrientes3804):- vive(Pers,boedo).

    + +
      +
    1. En el mismo programa, quiero decir que un departamento es alternativa para otro si sale exactamente 5000 pesos menos. En este caso tengo que hacer una cuenta que es la diferencia entre los precios; sé que el resultado de esa cuenta tiene que ser exactamente 5000.
    2. +
    + +

    Entonces, ¿pongo

    + +

       esAlternativa(Depto1,Depto2):- precio(Depto1,Pr1), precio(Depto2,Pr2), Dif is Pr2 - Pr1, Dif = 5000.

    + +

    o

    + +

       esAlternativa(Depto1,Depto2):- precio(Depto1,Pr1), precio(Depto2,Pr2), Dif is Pr2 - Pr1, Dif is 5000.

    + +

    ? Noooooo, el 5000 ya lo sé, no necesito pasarlo por la variable Dif. O sea

    + +

       esAlternativa(Depto1,Depto2):- precio(Depto1,Pr1), precio(Depto2,Pr2), 5000 is Pr2 - Pr1.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/lombardizacion.html b/wiki/articles/lombardizacion.html new file mode 100644 index 0000000000..a58f1411ee --- /dev/null +++ b/wiki/articles/lombardizacion.html @@ -0,0 +1,359 @@ + + + + + + + + + + + Lombardizacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Lombardizacion +

    +
    + + + +
    +

    Dícese de aquella actitud donde una propuesta viene siempre acompañada de un compromiso de acción. Es decir, una persona lombardizada es aquella que cuando hace una propuesta, se compromete a que esa propuesta se lleve a cabo. La Lombardización acepta como compromiso diversas actitudes que incluyen desde llevarlo a cabo completamente uno mismo hasta el movilizar gente para hacerlo.

    + +

    El término Lombardización proviene de la palabra Lombardi, tambien conocida como “apellido de Carlono”, en honor a Carlos “Carlono” “Gran Vikingo” Lombardi, perteneciente a este grupo. El orígen del uso de este vocablo se debe a…

    + +

    La Lombardización se ha extendido durante años en muchos grupos de personas. El típico grito de guerra con el que estas personas extienden estas creencias es “¡Lombardizate!”

    + +

    Ejemplos de Lombardización

    + +

    Hablando de escribir una entrada en la wiki:

    + +

    No Lombardizado: “Deberíamos tener una página en la wiki que explique la Lombardización a los mas nuevitos”.

    + +

    Lombardizado: “Che, escribí esta página en la wiki que explica la Lombardización para los mas nuevitos”.

    + +

    Para conseguir alguien que de una clase:

    + +

    No Lombardizado: “Che, hay que dar la clase de polimorfismo”

    + +

    Lombardizado: “Che, ¿puedo ayudar a dar la clase de polimorfismo? No me animo a darla solo”

    + +

    Misconcepciones Comunes

    + +

    La “lombardización” no significa: “eh, gato, por qué en lugar de chamuyar no te ponés a hacer algo, gil!”

    + +

    Originalmente no era esa la idea. Lombardización es lo que en los círculos de la chetez empresarial se llama “empowerment” (pfff). Aplica cuando alguien viene con una idea pero su idea no pasa de eso, de una propuesta, entonces “lombardizate” significa: “si tenés una buena idea, no esperes a que otro la lleve a cabo o a que un comité de notables le de su bendición, empujala vos, hacelo”. Frecuentemente eso pasaba con los más jóvenes o recién llegados al grupo, que tal vez por no conocer la mecánica interna esperaba que las decisiones las tomaran los más viejos y no se animaba a tener más iniciativa. Entonces lombardizar es justamente hacer que este grupo funcione sin depender de uno que centraliza o que toma decisiones o que no se puede hacer nada sin tener su visto bueno.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/macros-scala.html b/wiki/articles/macros-scala.html new file mode 100644 index 0000000000..82aabe3db2 --- /dev/null +++ b/wiki/articles/macros-scala.html @@ -0,0 +1,429 @@ + + + + + + + + + + + Macros en Scala + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Macros en Scala +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Introducción

    + +

    Macros es una herramienta muy poderosa que permite definir reescrituras de AST (Abstract Syntax Tree) y está presente en +muchos lenguajes y tecnologías. A grandes razgos, la útilidad de las macros consiste en tomar una construcción sintáctica +válida y reemplazarla por otra en tiempo de compilación, permitiendo así que la sintaxis que normalmente construiría un +cierto programa construya otro totalmente diferente. En Scala, la utilización de macros está definida en el paquete

    + +
    +
    +
    +      scala.language.experimental.macros
    +
    +    
    +
    +
    + +

    el cual debe ser importado para poder trabajar.

    + +

    Una macro de Scala se compone de dos partes: Una declaración y una implementación. Al momento de compilar, +los usos de la función declaración son procesados para reemplazarlos por el resultado de aplicar la función implementación. +Definir la declaración de una macro es muy similar a definir una función común pero, en lugar del cuerpo, se utiliza la +palabra clave macro seguida del nombre de la función implementación.

    + +
    +
    +
    +        // declaración
    +  def miMacro(parametro1: String, parametro2: Int) = macro miMacro_impl
    +  
    +  // implementación
    +  def miMacro_impl(c: Context)(parametro1: c.Expr[String], parametro2: c.Expr[Int]) = ???
    +
    +    
    +
    +
    +

    Whitebox y Blackbox macros

    + +

    Existen 2 tipos de macros, las llamadas “de caja blanca” o whitebox y las “de caja negra” o blackbox. La diferencia entre +los dos enfoques es que las macros de caja negra se usan cuando puedo definir claramente una firma para la función que quiero +implementar usando macros, mientras que las de caja blanca se usan cuando no puedo definir dicha firma. +Las macros de caja blanca son más flexibles pero menos seguras, ya que no pueden tiparse y van a ser discontinuadas en +versiones futuras de Scala, por esa razón vamos a concentrarnos en las definiciones de caja negra.

    + +

    Para elegir uno de estos dos enfoques es necesario importar el paquete correspondiente

    + +
    +
    +
    +      import scala.reflect.macros.whitebox
    +
    +    
    +
    +
    +

    para las de caja blanca y

    + +
    +
    +
    +      import scala.reflect.macros.blackbox
    +
    +    
    +
    +
    + +

    para las de caja negra.

    + +

    La clase Context que se usó en el código anterior está definida en estos paquetes.

    + +

    Mirando el ejemplo, se puede ver que hay una relación entre el tipo de la declaración de la macro y su implementación que, +además de recibir un parámetro Context, espera también un parámetro por cada parámetro de la declaración que debe tener +el mismo nombre y un tipo de expresión que coincida. creado a partir del contexto.

    + +

    Usos

    + +

    Veremos que hay varias maneras de colgarse del proceso de compilador, por lo que tenemos distintos tipos de macros +propuestos por scala, solo que en este caso nos estaremos enfocando en uno de los tipos de macros. Otra consideración a tener en cuenta es que la interfaz que tenemos de macros como la de reflection en scala puede ir variando en el tiempo, ya que son aún implementaciones experimentales y no se ha llegado a un estado final de como sería la implementación definitiva.

    + +

    Las macros han sido utilizados durante la versión 2.10 de Scala, tanto para aplicaciones de investigación como industriales, +y la conclusión según (Burmako), es que las macros han sido útiles para aplicaciones tales como:

    + +
      +
    • Code Generation
    • +
    • Implementation of DSLs
    • +
    • Static checking among others
    • +
    + +

    Mas información

    + +

    Ver más en detalle sobre macros en scala 2.10 en el siguiente link

    + +
    +

    Bibliografía

    + +
    1. Burmako, Eugene. Scala Macros: Let Our Powers Combine! On How Rich Syntax and Static Types Work with Metaprogramming.
    +
    + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/manejo-de-booleanos-en-haskell.html b/wiki/articles/manejo-de-booleanos-en-haskell.html new file mode 100644 index 0000000000..7e5cdedb49 --- /dev/null +++ b/wiki/articles/manejo-de-booleanos-en-haskell.html @@ -0,0 +1,440 @@ + + + + + + + + + + + Manejo de booleanos en haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Manejo de booleanos en haskell +

    +
    + + + +
    +

    El Tipo Bool

    + +

    Los booleanos son datos que representan la condición de verdad o falsedad.

    + +

    Recordemos que even es una función que recibe un número, y devuelve un booleano. (True si el número es par)

    + +

    Hagamos estas consultas en la consola (El simbolito > al inicio de la línea indica que se está haciendo una consulta):

    + +
    > even 6 
    +True
    +> not True
    +False
    +> not False
    +True
    +
    + +

    Aquí se ve que not es una función recibe un Bool (y que devuelve el booleano opuesto).

    + +

    Hay otras funciones que devuelven booleanos:

    + +
    > 5 < 1
    +True
    +> "mama" == "papa"
    +False
    +
    + +

    Entonces, si queremos que una función devuelva un booleano, basta con devolver el mismo resultado que obtuvimos. Por ejemplo,

    + +
    --"la golondrina pepita está empachada si su energía es mayor que 100"
    +estaEmpachada energia = energia > 100
    +
    + +

    Conjunción y Disjunción Lógica

    + +
    > True || False
    +True
    +> True && False
    +False
    +
    + +

    Para saber si el 6 es par y divisible por 3:

    + +
    > even 6 && (esDivisible 6 3)
    +True
    +
    + +

    Errores Comunes

    + +

    “true” vs true vs True

    + +

    En Haskell,

    + +
      +
    • true es un nombre de variable ó de función. Si trato de usarlo, me va a tirar el error “Not in Scope”.
    • +
    + +
    > not true
    +``Not in scope: `true'``
    +
    + +
      +
    • “true” es un String, por lo que si se lo mando a una función que espera un booleano, va a haber un error de tipos:
    • +
    + +
    > not "true"
    +`` Couldn't match expected type `Bool' ``
    +`` with actual type `[Char]' ``
    +
    + +
      +
    • True es la manera correcta de referirse al booleano. True es un Constructor del tipo de dato Bool.
    • +
    + +
    > not True
    +False
    +
    + +

    Problemas con Booleanos y Guardas

    + + + +

    Mal Uso de Booleanos (algo == True, etc.)

    + +

    Una variante de los problemas con Guardas es lo siguiente:

    + +
    desaprueba nota = estaAprobada nota == False
    +pierdePromocion nota = estaAprobada nota == True && nota < 8
    +
    + +

    Ese código está mal. ¿Por qué? Porque estaAprobada ya devuelve un Booleano. De la misma manera la función menor también devuelve un Booleano. Entonces, en el caso de pierdePromocion, está demás la comparación por True. Y en el caso del desaprobada, si lo que necesito es el opuesto del booleano, entonces debo usar la función not:

    + +
    desaprueba nota = not (estaAprobada nota)
    +pierdePromocion nota = estaAprobada nota && nota < 8
    +
    + +

    Ese código es el correcto. Comprobamos así que funcionan igual:

    + +
    > estaAprobada 7 == True
    +True
    +> estaAprobada 7
    +True
    +> estaAprobada 3 == False
    +True
    +> not (estaAprobada 3)
    +True
    +
    + +

    Además, algo muy importante, es más expresivo usar el not, ya que se lee: “desaprueba una nota cuando no está aprobada” desaprueba nota = not (estaAprobada nota) .

    + +

    Y por último, estoy ocultando un poquito el cómo . Es decir, nos concentramos en la idea de “negación”, más que en comparar booleanos por ==True o ==False. Como dice Fidel, un profe de la Universidad Nacional de Quilmes: ¡No le tengamos miedo al booleano!

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/manejo-de-booleanos-en-smalltalk.html b/wiki/articles/manejo-de-booleanos-en-smalltalk.html new file mode 100644 index 0000000000..ea4c1fafc7 --- /dev/null +++ b/wiki/articles/manejo-de-booleanos-en-smalltalk.html @@ -0,0 +1,446 @@ + + + + + + + + + + + Manejo de booleanos en smalltalk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Manejo de booleanos en smalltalk +

    +
    + + + +
    +

    Los Booleanos como objetos

    + +

    Los booleanos son objetos que representan la condición de verdad ó falsedad.

    + +

    Recordemos que even es un mensaje que entienden los números, y devuelve un booleano. (true si el número es par)

    + +

    6 even. "devuelve true" +true not. "devuelve false" +false not. "devuelve true"

    + +

    Aquí se ve que not es un mensaje que entienden los booleanos (y que devuelve el booleano opuesto).

    + +

    Hay otros mensajes que devuelven booleanos:

    + +

    5 < 1 "devuelve false" +1 between: 0 and: 3 "devuelve true"

    + +

    Entonces, si queremos que un método devuelva un booleano, basta con devolver el mismo resultado que obtuvimos. Por ejemplo,

    + +

    "la golondrina pepita está empachada si su energía es mayor que 100" +>>estasEmpachada +    ^ energia > 100.

    + +

    Conjunción y Disjunción Lógica

    + +

    true | false "devuelve true" +true & false "devuelve false"

    + +

    Para saber si el 6 es par y divisible por 3:

    + +

    6 even & (6 isDivisibleBy: 3) "devuelve true"

    + +

    Agregando Vitaminas

    + +

    Además de los mensajes binarios & y |, tenemos los mensajes and: y or:, que en vez de recibir un booleano, reciben un bloque de código (que adentro tiene un booleano). Veamos:

    + +

    6 even | 5 even "devuelve true" +6 even or: [5 even]. "devuelve true"

    + +

    5 even & 6 even. "devuelve false" +5 even and: [6 even]. "devuelve false"

    + +

    ¿Para qué queremos estos mensajes? Porque son “lazy”. Es decir, tienen algo de evaluación perezosa. Ésto significa que si estoy haciendo un “or” y el receptor ya es verdadero, no hace falta analizar el segundo elemento (el or es verdadero):

    + +

    5 > 1 or: [7 * 2]. "devuelve true, sin analizar el bloque basura" +5 > 1 | (7 * 2). "tira error, porque 14 no es un booleano"

    + +

    Y si estoy haciendo un “and” y el receptor es falso, no hace falta analizar el segundo elemento (el and es falso):

    + +

    5 even and: [4]. "devuelve false, sin analizar el bloque basura" +5 even & 4. "tira error, porque 4 no es un booleano"

    + +

    En general, es buena práctica utilizar and: y or:.

    + +

    Para pensar

    + +

    ¿Qué pasaría en cada caso si dentro del bloque hay una operación con efecto sobre el estado del sistema? La respuesta a ésta pregunta nos va a ayudar a entender por qué no está bueno tener efecto cuando hacemos un and: ó un or:.

    + +

    Errores Comunes

    + +

    true vs True

    + +

    En el ambiente hay un objeto llamado true y otro llamado True.

    + +

    El que representa el valor de verdad, el “sí”, es el true con minúscula.

    + +

    True es la clase de la cual true es instancia. Lo que empieza en mayúscula es casi-casi siempre nombre de clase (o de variable de clase, eso lo vemos cerca del final de la parte de objetos).

    + +

    Si uno se confunde y usa True, claro, el ifTrue: no anda bien, porque el mensaje ifTrue: lo entiende el objeto true, no su clase.

    + +

    ifTrue: [^true], ¿está bien?

    + +

    Robin siendo abofeteado por Batman. Debería hacer mejor uso de booleanos. Miremos este método que está en una clase cuyas instancias entienden el mensaje pais

    + +

       mismoPaisCon: unaCiudad  +       ((self pais) = (unaCiudad pais)) +       ifTrue: [^true] +       ifFalse: [^false]

    + +

    y supongamos que la comparación

    + +

       ((self pais) = (unaCiudad pais))

    + +

    da true.

    + +

    ¿Qué quiere decir que “da true”? Que si evalúo esa parte, el objeto que me devuelve es el objeto true, el único objeto true de Smalltalk. A ese le estoy diciendo ifTrue:ifFalse:, y en el bloque que ejecuta si es true … le digo que devuelva true, o sea que devuelva el mismo objeto al que le dije ifTrue:ifFalse:. Lo mismo con el false.

    + +

    En resumen, el ifTrue:ifFalse: sobra, este método se puede escribir así

    + +

       mismoPaisCon: unaCiudad  +       ^(self pais) = (unaCiudad pais)

    + +

    y listo.

    + +

    === ^(algo = true) === Una variante del caso anterior es un código como este, dentro de una clase cuyas instancias entienden los mensajes estaLibre y estaAndando

    + +

       puedeUsarse +       ^(self estaLibre = true) & (self estaAndando = true)

    + +

    Analicemos la parte

    + +

       (self estaLibre = true)

    + +

    La expresión self estaLibre hace lo único que puede hacer una expresión en Smalltalk: devolver un objeto. ¿Qué objeto puede ser ese?

    + +

    1. +Si la condición es cierta, entonces el objeto que devuelve es el objeto true, el único objeto en un ambiente Smalltalk que representa el valor de verdad “cierto”. Si a ese objeto le pregunto = true, ¿qué objeto va a ser el resultado?

    + +

    Si pregunto si dos objetos son iguales, o me va a responder true, o me va responder false, no hay otra. En este caso, true es el mismo objeto que true, o sea el = da cierto, o sea … devuelve ¡true!, que es el mismo objeto que obtenía con

    + +

       (self estaLibre)

    + +

    2. +Ahora supongamos que la condición no es cierta, en ese caso me devuelve el objeto false, si a false le digo = true el resultado de eso es el objeto false, que otra vez es lo mismo que obtengo poniendo solamente

    + +

       (self estaLibre)

    + +

    Consecuencia +El mismo análisis lo puedo hacer con

    + +

       (self estaAndando = true)

    + +

    y la conclusión es que el método puede escribirse así

    + +

       puedeUsarse +       ^(self estaLibre) & (self estaAndando)

    + +

    En esta versión estamos manejando mejor los booleanos, porque aceptamos que el resultado de self estaLibre es un booleano, que va a ser true o false, y que va a entender & con el otro booleano como parámetro.

    + +

    Un caso parecido

    + +

    ¿Y si en lugar de estaLibre tengo estaOcupado, qué hago, pongo

    + +

       puedeUsarse +       ^(self estaOcupado = false) & (self estaAndando = true)

    + +

    nooooo … quiero el booleano “contrario” al resultado de self estaLibre, para eso los booleanos entienden not, en este caso

    + +

       puedeUsarse +       ^(self estaOcupado not) & (self estaAndando)

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/manejo-de-booleanos.html b/wiki/articles/manejo-de-booleanos.html new file mode 100644 index 0000000000..97ce049fe2 --- /dev/null +++ b/wiki/articles/manejo-de-booleanos.html @@ -0,0 +1,333 @@ + + + + + + + + + + + Manejo de booleanos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Manejo de booleanos +

    +
    + + + +
    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/manejo-de-errores.html b/wiki/articles/manejo-de-errores.html new file mode 100644 index 0000000000..add42b3581 --- /dev/null +++ b/wiki/articles/manejo-de-errores.html @@ -0,0 +1,338 @@ + + + + + + + + + + + Manejo de errores + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Manejo de errores +

    +
    + + + +
    +
      +
    1. REDIRECCIÓN Excepciones
    2. +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/manejo-de-memoria-en-c.html b/wiki/articles/manejo-de-memoria-en-c.html new file mode 100644 index 0000000000..024a988cec --- /dev/null +++ b/wiki/articles/manejo-de-memoria-en-c.html @@ -0,0 +1,307 @@ + + + + + + + + + + + Manejo de memoria en c + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Manejo de memoria en c +

    +
    + + + +
    +

    https://github.com/jwise/minilib

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/maquina-virtual.html b/wiki/articles/maquina-virtual.html new file mode 100644 index 0000000000..cde407de58 --- /dev/null +++ b/wiki/articles/maquina-virtual.html @@ -0,0 +1,333 @@ + + + + + + + + + + + Maquina virtual + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Maquina virtual +

    +
    + + + +
    +

    Puede haber un poco de confusión con la palabra Máquina Virtual (VM).

    + +

    La imagen de Pharo corre sobre una máquina virtual, llamada Pharo VM o Squeak VM o Cog VM. Esta VM es un programa más o menos común y corriente, sobre el cual se carga una imagen de Pharo. Esta VM es indispensable.

    + +

    Mas allá de que existe una diferencia técnica enorme, en una primera aproximación podés comparar a la VM de Pharo con el intérprete de Hugs o swi-prolog: son programas responsables de ejecutar tu código. Luego, podés comparar a la imágen de Pharo con los archivos .pl o .hs: contienen código y datos de tu programa.

    + +

    Por otro lado, en el laboratorio de sistemas, la VM de Pharo está instalada directamente sobre el sistema operativo (un Windows), mientras que los interpretes de Haskell y Prolog están instalados, por cuestiones prácticas para la gente del laboratorio, en un sistema operativo virtualizado montado sobre una VM VMware, pero bien podrían haberlo instalado sobre el mismo Windows.

    + +

    VMsComparadas.png

    + +

    Esta última VM (VMWare) es de naturaleza totalmente distinta a la VM de Pharo: emula un hardware completo, y se la conoce como Máquina Virtual de Sistema. La máquina virtual de Pharo, en cambio, emula sólo algunos algunos aspectos del hardware, y tiene como única finalidad correr código en Smalltalk. Se la conoce como Máquina Virtual de Aplicación (en azul):

    + +

    Recalco que la virtualización en amarillo es totalmente opcional, en el labo está así porque ayuda a organizar el software para cada materia, pero normalmente en tu casa no vas a necesitar hacer eso para instalar el software de PDP.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/masa-de-pizza.html b/wiki/articles/masa-de-pizza.html new file mode 100644 index 0000000000..1506f21e78 --- /dev/null +++ b/wiki/articles/masa-de-pizza.html @@ -0,0 +1,327 @@ + + + + + + + + + + + Masa de pizza + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Masa de pizza +

    +
    + + + +
    +

    Cantidad: 4 pizzas

    + +

    Ingredientes:

    + +
      +
    • 1kg harina 000 o más ceros
    • +
    • 50 gr levadura
    • +
    • sal,
    • +
    • 4 cucharadas de aceite
    • +
    • salsa de tomate
    • +
    + +

    Pasos:

    + +
      +
    1. Diluir la levadura con un poquito de agua, una cucharada de azucar, una cucharada de harina, dejarla espumar (que se haga una esponja). Si después de un rato no esponja NO SIRVE. Tiene que quedar del mismo color.
    2. +
    3. Poner la harina en bol cacerola o palangana, hacer un hueco en el centro agregar 3 cucharadas de aceite (o 4) y una cucharada de sal alrededor (sobre la corona).
    4. +
    5. Poner la levadura sobre el aceite, agregar agua (medio litro de agua, de a poco) y mezclar, de adentro hacia afuera. Amasarla, golpearla hasta que quede blandita uniforma y que no se pegue en los dedos (o muy poquito).
    6. +
    7. Se pone en un bol, se tapa y se deja descansar. Hasta que esta el doble de su tamaño original (aproximadamente 20-30 minutos). NO PONER EN CORRIENTE DE AIRE.
    8. +
    9. Volver a masar, sacarle bien el gas. Separar en bollos. Aceitar los moldes. Estirar la masa en los moldes con la mano aceitada para que no se pegue. +
        +
      1. Si dejamos los bollos hay que taparlos bien con papel film
      2. +
      +
    10. +
    11. Cuando esta bien estirada ponerle muy poquitito de salsa (para que no se humedezca).
    12. +
    13. Dejar leudar hasta que vuelva a duplicar su volumen.
    14. +
    15. Poner en el horno bien caliente. Cuando hace piso, se le pone toda las cosas locas.
    16. +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/maven.html b/wiki/articles/maven.html new file mode 100644 index 0000000000..149415c01d --- /dev/null +++ b/wiki/articles/maven.html @@ -0,0 +1,633 @@ + + + + + + + + + + + Introducción a Maven + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Introducción a Maven +

    +
    + + + +
    +

    Maven es una herramienta que ayuda a desarrollar un proyecto basado en el entorno de una JDK (Java, Xtend, Scala, Groovy, etc.)

    + +

    Funcionalidades

    + +

    Maven cumple con las siguientes funciones principales que vamos a explicar en las siguientes secciones:

    + +
      +
    • Reificación de Proyecto / Artefacto en forma standard, declarativa y extensible
    • +
    • Manejo de Dependencias
    • +
    • Manejo del Ciclo de Vida del Artefacto, incluyendo releases
    • +
    + +

    Reificación de Proyecto/Artefacto

    + +

    Java no trabaja la idea de proyecto, no lo representa como concepto. Entonces, cada uno de los IDEs pensados para Java agregan su propia forma de definirlo: en el caso de Eclipse tenemos

    + +
      +
    • el archivo .classpath que define los directorios donde compilar y las dependencias que necesita
    • +
    • el archivo .project que contiene el nombre del proyecto, entre otras cosas
    • +
    + +

    Si nosotros trabajamos con otro IDE (como IntelliJ IDEA o NetBeans) tenemos que adaptar estos archivos para generar el proyecto con sus dependencias adecuadamente. Maven permite trabajar entre IDEs con su propio modelo de proyecto, que se guarda en el archivo pom.xml (de Project Object Model)

    + +

    Identificación de un proyecto Maven

    + +

    En el archivo pom se declaran, entre otras cosas, un identificador único de nuestro proyecto/artefacto, que resulta de la unión de tres identificadores:

    + +
      +
    • groupId: representa la organización autora/dueña del artefacto. Por ejemplo, los proyectos de Algoritmos 2 suelen usar el groupId org.uqbar.
    • +
    • artifactId: este campo define el nombre por el que se conoce al proyecto en sí mismo. Algunos ejemplos: commons-collections, eg-seguros-xtend, tp-futbol5-grupo01, etc.
    • +
    • versión: es el último componente del rompecabezas, dado que groupId:artifactId denota un único proyecto pero no alcanza para definir en qué versión del proyecto nos estamos parando. Se agrega entonces un número de versión para completar la información que Maven necesita para generar una identificación unívoca. Conviene seguir las reglas de versionado semántico, para liberar versiones productivas. A veces se suele acompañar de un sufijo RELEASE (para versiones estables) o SNAPSHOT (para versiones intermedias que pueden estar sujetas a cambios)
    • +
    + +

    A continuación un ejemplo básico.

    + +
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    +      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    +      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    +                          http://maven.apache.org/xsd/maven-4.0.0.xsd">
    +    <modelVersion>4.0.0</modelVersion>
    +
    +    <groupId>org.uqbar</groupId>
    +    <artifactId>uqbar-commons</artifactId>
    +    <version>1.1.2</version>
    +</project>
    +
    + +
    +

    Cuando se publica un componente, se empaquetan todas las clases compiladas (.class) en un archivo comprimido que tiene la extensión .jar (de Java Archive). Opcionalmente podemos tener un archivo comprimido extra con los fuentes.

    +
    + +

    Repositorios Maven

    + +

    Un repositorio Maven es un lugar donde están los artefactos Maven, estructurados en cierta forma estándar para hacer las descargas de las dependencias. Cuando instalamos Maven, se crea un repositorio Maven local en una carpeta que por defecto suele ser HOME/.m2. Si queremos ubicar al componente cuyo identificador es org.eclipse.xtend:org.eclipse.xtend.core:2.21.0.M1 podremos encontrarlo localmente en

    + +
    %M2_HOME%/repository
    +   └── org
    +       └── eclipse
    +             └── xtend
    +                  └── org.eclipse.xtend.core
    +                         ├─ 2.19.0 (otra versión)
    +                         └─ 2.21.0.M1 --> dentro de esta carpeta estará el .jar
    +
    + +
      +
    • recordemos que el identificador de un componente se arma a partir del groupId + el artifactId + la versión
    • +
    • se suele exportar como variable la carpeta HOME/.m2 con el nombre M2_HOME
    • +
    • en M2_HOME puede haber opcionalmente un archivo settings.xml que veremos más adelante
    • +
    • en la subcarpeta repository están todos los componentes que descargamos localmente
    • +
    + +

    Vemos un video de ejemplo, en una máquina Linux. El comportamiento en una máquina Windows es exactamente igual, hay que explorar los directorios incluyendo los que son ocultos, y navegar a partir de la carpeta de usuario.m2:

    + +

    repo maven local

    + +

    Relacionando proyectos maven desde el POM

    + +

    Es posible referenciar a otros proyectos maven desde un POM, esto es muy útil para cuando necesitamos

    + +
      +
    • declarar dependencias,
    • +
    • definir un proyecto padre,
    • +
    • agregar plugins
    • +
    + +

    a la hora de compilar nuestro proyecto.

    + +

    Dependencias

    + +

    Las dependencias se definen dentro de un tag <dependencies>:

    + +
    <project ...>
    +	<...>
    +	<dependencies>
    +		<dependency>
    +			<groupId>org.junit.jupiter</groupId>
    +			<artifactId>junit-jupiter-params</artifactId>
    +			<version>5.5.2</version>
    +			<scope>test</scope>
    +		</dependency>
    +	</dependencies>
    +
    + +

    En este caso, estamos definiendo que nuestro proyecto tiene como pre-requisito el componente junit-jupiter-params asociado a org.junit.jupiter. Si utilizamos Maven como un plugin de Eclipse

    + +
      +
    • agregamos la dependencia en el pom,
    • +
    • actualizamos el proyecto (Maven > Update project)
    • +
    • y eso dispara la descarga del componente al repositorio Maven local como vemos en el video
    • +
    + +

    descarga componente local

    + +

    Al agregar una dependencia a un proyecto es posible especificar el type (por ej., jar), el scope (por ejemplo: test), y si es o no optional.

    + +

    Parent project

    + +

    Otra variante es utilizar un proyecto padre mediante el tag <parent>, como ocurría en versiones anteriores de los ejemplos de Uqbar hasta 2019:

    + +
    <parent>
    +    <groupId>org.uqbar-project</groupId>
    +    <artifactId>uqbar-xtend-parent</artifactId>
    +    <version>2.17.1</version>
    +</parent>
    +
    + +

    El parent project permite reutilizar definiciones comunes entre varios proyectos. En este caso particular, uqbar-xtend-parent (el nombre que le dimos a este artefacto) sirve para definir

    + +
      +
    • que utilizaremos la versión 2.17.0 de Xtend
    • +
    • con una dependencia para correr tests unitarios
    • +
    • compilando a JDK 1.8
    • +
    + +

    Plugins

    + +

    Los plugins de Maven no solo permiten reutilizar lógica sino que además ejecutan acciones cuando son descargados. Así funciona el núcleo central de Maven: uno de los plugins más conocidos es clean, que elimina el directorio de destino (en el caso de Xtend, donde están los archivos Java y los .class que se generan a partir de los fuentes originales). Otro plugin conocido es Surefire, que ejecuta los tests de un proyecto basado en JDK.

    + +


    +Distintos proyectos maven requieren/ofrecen distintos settings al ser referenciados como plugins. Veamos un ejemplo de la configuración del plugin de xtend:

    + +
      <plugins>
    +		<plugin>
    +      <groupId>org.eclipse.xtend</groupId>
    +      <artifactId>xtend-maven-plugin</artifactId>
    +      <version>2.20.0</version>
    +      <executions>
    +        <execution>
    +          <goals>
    +            <goal>compile</goal>
    +            <goal>testCompile</goal>
    +          </goals>
    +          <configuration>
    +            <outputDirectory>${project.build.directory}/xtend-gen/main</outputDirectory>
    +            <testOutputDirectory>${project.build.directory}/xtend-gen/test</testOutputDirectory>
    +          </configuration>
    +        </execution>
    +      </executions>
    +		</plugin>
    +  </plugins>
    +
    + +

    Aquí le estamos indicando a maven las características de la ejecución del plugin, es decir:

    + +
      +
    • los goals (metas/capacidades del plugin). Este es un plugin de compilación por lo que indica los valores compile y testCompile.
    • +
    • la configuración de las rutas del filesystem para los archivos java compilados.
    • +
    + +


    +Lo recomendable en cada caso es siempre revisar la documentación oficial del proyecto maven que queremos referenciar, para entender qué settings son requeridos o convenientes para nuestro proyecto.

    + +

    Dependencias transitivas

    + +

    Un detalle no menor de la resolución de dependencias de maven es que también funciona para las dependencias transitivas.

    + +

    Por ejemplo:

    + +
      +
    • proyectoA –> proyectoB
    • +
    • proyectoB –> proyectoC
    • +
    • proyectoC –> proyectoD, proyectoE, proyectoF
    • +
    + +

    Al resolver las dependencias, el proyectoA necesitará descargar los componentes B, C, D, E y F. Incluso podríamos requerir diferentes versiones de los mismos componentes.

    + +


    +Noten que un proyecto comercial “normal” o mediano, puede incluir decenas y hasta cientos de dependencias. Eclipse permite integrar todas las definiciones de un pom junto con sus parents en la solapa Effective POM:

    + +

    effective POM

    + +

    Repositorios remotos

    + +

    La pregunta que puede hacerse el lector es: ¿desde dónde se descargan los componentes la primera vez? ¿Cómo es que Maven sabe dónde ubicarlos, y cómo saber a qué versión apuntar? Por defecto, Maven apunta a un repositorio central donde se suben todos los componentes que utiliza la comunidad que trabaja con la JDK: https://repo.maven.apache.org/maven2/

    + +

    Cuando tenemos dudas sobre las versiones de algún componente, podemos hacer una búsqueda en

    + +
    http://search.maven.org
    +
    + +

    por ejemplo, podemos buscar el componente uqbar-domain, que direcciona a https://search.maven.org/search?q=uqbar-domain. Allí tenemos todos los releases, con sus fechas correspondientes:

    + +

    search maven

    + +

    Para publicar un componente en el repositorio Sonatype que está relacionado con Maven Central, hay que cumplir algunas reglas. En particular, para los componentes Uqbar hay que seguir estas instrucciones.

    + +

    Definiendo repositorios remotos

    + +

    En nuestro pom.xml podemos definir repositorios adicionales donde encontrar componentes de Maven:

    + +
    <project>
    +  ...
    +  <repositories>
    +    <repository>
    +      <id>my-internal-site</id>
    +      <url>http://myserver/repo</url>
    +    </repository>
    +  </repositories>
    +  ...
    +</project>
    +
    + +

    Otra opción es escribir esto en el archivo settings.xml del directorio raíz de nuestro M2, como cuenta este artículo.

    + +

    Flujo general de descarga de componentes

    + +

    A continuación mostraremos el algoritmo que utiliza Maven para encontrar las dependencias de nuestro proyecto: si no lo tenemos en nuestro repositorio local, lo irá a buscar al repositorio Maven Central, y en última instancia, en los repositorios adicionales definidos por nuestro proyecto o la configuración general de Maven (el archivo settings.xml).

    + +

    flujo general de descarga de componentes Maven

    + +

    Ejecutando maven desde la consola

    + +

    Una alternativa es trabajar directamente con Maven desde la consola, algo que puede ser útil para automatizar tareas, como cuando trabajemos con herramientas de integración continua.

    + +
    mvn clean compile
    +
    + +

    Esto ejecuta varios plugins en forma sincronizada:

    + +
      +
    • por un lado borra los directorios de destino, como hemos contado en el párrafo plugins
    • +
    • y luego compila los fuentes del proyecto, lo cual implica descargarse las dependencias, y en el caso del plugin de Xtend, convertir los archivos .xtend a .java (y luego generar los .class)
    • +
    + +

    Si queremos ver el árbol de dependencias transitivas, podemos escribir

    + +
    mvn dependency:tree
    +
    + +

    Pero ¿cómo sabemos qué comando debemos ejecutar? Para eso hay que entender el ciclo de vida de un build de Maven.

    + +

    Ciclos de build

    + +

    Maven está pensado para todo el ciclo de vida del proyecto. Lo vamos a usar para compilar, para generar código (de ser necesario), para correr los tests, para empaquetar, y hasta para publicar nuestros artefactos generando releases con trazabilidad.

    + +

    Maven define un conjunto de etapas en la construcción (build) de nuestro proyecto. Resumimos algunas acá:

    + +
      +
    • generate-sources: generar código, previo a compilación.
    • +
    • compile: compila el código fuente.
    • +
    • test: ejecuta los test cases
    • +
    • package: genera un paquete con el código (.jar por ejemplo)
    • +
    • install: hace público el paquete en nuestro repositorio local (ver repositorios locales en las siguiente sección)
    • +
    • deploy: publica el artefacto en un repositorio remoto (ver repositorios locales en las siguiente sección)
    • +
    + +

    Podemos indicar a Maven que ejecute hasta cierta fase. Por ejemplo:

    + +
    mvn compile
    +
    + +

    Va a ejecutar las dos primeras fases.

    + +
    mvn test
    +
    + +

    Las tres primeras. Es decir es igual a mvn compile + correr los tests.

    + +


    +De la misma manera podemos trabajar en Eclipse con el plugin M2:

    + +

    maven m2 build

    + +

    Relación entre plugins y ciclos del build

    + +

    A continuación dejamos un diagrama básico que muestra la relación entre plugin y el ciclo de vida del build:

    + +

    Maven Plugin and Build Lifecycle

    + +

    El gráfico no incluye plugins que estamos usando en Algoritmos 2: Xtend, cobertura de tests, etc. pero sirve como referencia para entender qué goals se ejecutarán en base al comando Maven pedido.

    + +

    Resumen general de la arquitectura Maven

    + +

    maven architecture

    + +

    Documentación oficial

    + +

    Para más información recomendamos leer la documentación oficial del proyecto Maven:

    + + + +


    +Y estos links:

    + + + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/mejorar-la-experiencia-del-pharoer.html b/wiki/articles/mejorar-la-experiencia-del-pharoer.html new file mode 100644 index 0000000000..eda4dda0ce --- /dev/null +++ b/wiki/articles/mejorar-la-experiencia-del-pharoer.html @@ -0,0 +1,323 @@ + + + + + + + + + + + Mejorar la experiencia del pharoer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Mejorar la experiencia del pharoer +

    +
    + + + +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/mensajes-de-colecciones.html b/wiki/articles/mensajes-de-colecciones.html new file mode 100644 index 0000000000..97b3af5132 --- /dev/null +++ b/wiki/articles/mensajes-de-colecciones.html @@ -0,0 +1,552 @@ + + + + + + + + + + + Mensajes de colecciones + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Mensajes de colecciones +

    +
    + + + +
    +

    Este es un pequeño resumen de mensajes que entiende una colección. Lo que sigue sirve para todos los sabores de colecciones.

    + +

    ¿Qué puedo hacer con los conjuntos de objetos? Muchas cosas, las colecciones entienden mensajes muy útiles para ayudarnos a abstraernos un poquito. Vamos a separarlos en los que tienen efecto colateral sobre la colección receptora y los que no.

    + +

    Con efecto

    + +

    Estos mensajes alteran a la colección que recibe el mensaje. Si no quiero perder la colección original puedo o bien copiar la colección mandándole shallowCopy y luego usar estos mensajes, o replantearme si no quería usar alguno de los mensajes de colecciones sin efecto :)

    + +

    Agregarle objetos

    + +

    Smalltalk

    + +

    pajaros add: pepita.

    + +

    Wollok

    + +

    pajaros.add(pepita)

    + +

    También existe el mensaje addAll: en Smalltalk y addAll(conjunto) en Wollok que recibe otra colección y agrega todos los elementos del parámetro a la colección receptora.

    + +

    Smalltalk

    + +

    pajaros addAll: picaflores

    + +

    Wollok

    + +

    pajaros.addAll(picaflores)

    + +

    Quitarle objetos

    + +

    Smalltalk

    + +

    pajaros remove: pepita.

    + +

    Wollok

    + +

    pajaros.remove(pepita)

    + +

    Análogamente al addAll:/addAll(conjunto), existe el removeAll:/removeAll(conjunto) que le quita a la receptora todos los que estén en la colección parametrizada.

    + +

    Sin efecto

    + +

    Estos mensajes se pueden mandar tantas veces como queramos sin miedo de alterar la colección receptora.

    + +

    Saber cuántos objetos tiene

    + +

    Smalltalk

    + +

    pajaros size.

    + +

    Wollok

    + +

    pajaros.size()

    + +

    ¿Que me devuelve? Un objeto número con la cantidad de objetos que conoce.

    + +

    Preguntarle si tiene un objeto

    + +

    Smalltalk

    + +

    pajaros includes: pepita. 

    + +

    Wollok

    + +

    pajaros.contains(pepita)

    + +

    ¿Que me devuelve? Un objeto booleano, true o false

    + +

    Unirlo o intersectarlo con otro conjunto

    + +

    Smalltalk

    + +

    golondrinas union: picaflores.

    + +

    Wollok

    + +

    golondrinas.union(picaflores)

    + +

    ¿Que me devuelve? Una nueva colección con la unión de ambas.

    + +

    Smalltalk

    + +

    aves intersection: voladores.

    + +

    Wollok

    + +

    aves.intersection(voladores)

    + +

    ¿Que me devuelve? Una nueva colección con la intersección de ambas.

    + +

    Siendo que la unión y la intersección está pensada para conjuntos matemáticos, estos mensajes sólo lo entienden los sets.

    + +

    Además en Wollok puede hacerse:

    + +

    golondrinas + picaflores

    + +

    Que retorna la concatenación de ambos conjuntos, retornando una colección del mismo sabor que la receptora.

    + +

    Seleccionar los elementos que cumplen con un criterio

    + +

    Smalltalk

    + +

    pajaros select: [:unPajaro | unPajaro estaDebil ].

    + +

    usuarios select: [:unUsuario | unUsuario deuda > 1000].

    + +

    Wollok

    + +

    pajaros.filter({unPajaro => unPajaro.estaDebil()})

    + +

    usuarios.filter({unUsuario => unUsuario.deuda() > 1000})

    + +

    ¿Que me devuelve? Una nueva colección con los objetos que cuando se los evalúa con el bloque, dan true.

    + +

    Buscar algún elementos que cumpla con un criterio

    + +

    Smalltalk

    + +

    pajaros detect: [:unPajaro | unPajaro estaDebil ].

    + +

    Wollok

    + +

    pajaros.find({unPajaro => unPajaro.estaDebil()})

    + +

    ¿Que me devuelve? Un objeto de la colección que cuando se lo evalúe con el bloque, de true.

    + +

    ¿Qué pasa si no hay ningún objeto que cumpla la condición? Explota, lo cual tiene sentido porque no sabe qué hacer si no lo tiene. Por eso existe otra versión en la cual podemos decirle qué devolvernos si no hay ninguno.

    + +

    Smalltalk

    + +

    pajaros detect: [:unPajaro | unPajaro estaDebil ] ifNone: [ pajaros anyOne ].

    + +

    Wollok

    + +

    pajaros.findOrElse({unPajaro => unPajaro.estaDebil()}, { pajaros.anyOne() })

    + +

    Recolectar el resultado de hacer algo con cada elemento

    + +

    Smalltalk

    + +

    pajaros collect: [:unPajaro | unPajaro ultimoLugarDondeFue].

    + +

    Wollok

    + +

    pajaros.map({unPajaro => unPajaro.ultimoLugarDondeFue()})

    + +

    ¿Que me devuelve? Una nueva colección con los objetos que devuelve el bloque al aplicarlo con cada elemento.

    + +

    Verificar si todos los elementos de la colección cumplen con un criterio

    + +

    Smalltalk

    + +

    pajaros allSatisfy: [:unPajaro | unPajaro estaDebil].

    + +

    Wollok

    + +

    pajaros.all({unPajaro => unPajaro.estaDebil()})

    + +

    ¿Que me devuelve? un booleano que indique si todos los objetos de la colección dan true al evaluarlos con el bloque.

    + +

    Verificar si algún elemento de la colección cumple con un criterio

    + +

    Smalltalk

    + +

    pajaros anySatisfy: [:unPajaro | unPajaro estaDebil].

    + +

    Wollok

    + +

    pajaros.any({unPajaro => unPajaro.estaDebil()})

    + +

    ¿Que me devuelve? un booleano que indique si alguno de los objetos de la colección da true al evaluarlo con el bloque.

    + +

    Reducir una colección haciendo algo un elemento y el resultado de la reducción con el elemento anterior

    + +

    Si queremos evaluar un bloque de dos parámetros con cada elemento de la colección, usando como primer parámetro la evaluación previa, y como segundo parámetro ese elemento (o sea, lo que en funcional vimos como fold)

    + +

    Smalltalk

    +
    pajaros inject: 0 into: [:inicial :unPajaro | inicial + unPajaro peso].  "sumatoria de pesos"
    +pajaros inject: (pajaros anyOne) into: [:masFuerte :unPajaro | 
    +  (unPajaro energia < masFuerte energia) ifTrue: [unPajaro] ifFalse: [masFuerte]] "maximo segun energia"
    +
    + +

    Wollok

    +
    pajaros.fold(0, {inicial, unPajaro => inicial + unPajaro.peso()}) // sumatoria de pesos
    +pajaros.fold(pajaros.anyOne(), {masFuerte, unPajaro => 
    +  if(unPajaro.energia() < masFuerte.energia()) unPajaro else masFuerte }) // maximo segun energia
    +
    + +

    ¿Que me devuelve? La ultima evaluación del bloque.

    + +

    ¿Para qué me sirve? Para muchas cosas: obtener el que maximice o minimice algo, obtener el resultado de una operación sobre todos (p.ej. sumatoria), y más. Por lo general existen operaciones de más alto nivel para la mayoría de las reducciones más comunes, de ser así obviamente es preferible usar esos mensajes en vez de hacer la reducción.

    + +

    Por ejemplo, en Wollok podríamos haber hecho directamente:

    + +

    pajaros.sum({unPajaro => unPajaro.peso()}) +pajaros.max({unPajaro => unPajaro.energia()})

    + +

    Obtener una colección de otro sabor

    + +

    En Smalltalk existen los mensajes asSet, asBag, asOrderedCollection y asSortedCollection: que retornan una colección nueva a partir de la receptora que tiene otras características (ver sabores de colecciones). En particular asSet y asSortedCollection: son de uso más común para quitar repetidos u ordenar en base a un criterio respectivamente.

    + +

    usuarios.asSortedCollection: [:usuarioJoven :usuarioViejo | usuarioJoven edad < usuarioViejo edad ]

    + +

    En Wollok, al sólo haber sets y listas, lo que ambas entienden son asSet() y asList(). Las listas ordenadas por un criterio pueden obtenerse mediante el mensaje sortedBy(criterio), que retorna una nueva colección con los elementos de la receptora ordenadas según el bloque recibido.

    + +

    usuarios.sortedBy({ usuarioJoven, usuarioViejo => usuarioJoven.edad() < usuarioViejo.edad() })

    + +

    A su vez en Wollok también existe el mensaje sortBy(criterio) que se diferencia en que en vez de retornar una nueva colección ordenada de esa forma, modifica la colección receptora para quedar ordenada así. O sea, produce un efecto colateral.

    + +

    ¿Y la iteración?

    + +

    El mensaje do: en Smalltalk o forEach(bloque) en Wollok, sirve para hacer algo con cada objeto de la colección. Este mensaje en sí mismo no tiene efecto colateral, pero tampoco tiene un valor de retorno que pueda interesarnos. Entonces, ¿cuándo se usa? Sólo tiene sentido usar este mensaje cuando lo que queremos hacer sobre cada elemento (o sea, el bloque) sí produce un efecto.

    + +

    Smalltalk

    + +

    pajaros do: [:unPajaro | unPajaro vola: 100 ].

    + +

    Wollok

    + +

    pajaros.forEach({unPajaro => unPajaro.vola(100)})

    + +

    Yo no pretendo recolectar resultados, sólo quiero que pasen cosas con cada elemento.

    + +

    Importante: no usar el do:/forEach para todo, los mensajes que vimos anteriormente son abtracciones mucho más ricas que nos permiten concentrarnos en nuestro objetivo y no en el algoritmo para lograr el resultado, seamos declarativos!

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/mensajes-y-metodos.html b/wiki/articles/mensajes-y-metodos.html new file mode 100644 index 0000000000..880807ac2b --- /dev/null +++ b/wiki/articles/mensajes-y-metodos.html @@ -0,0 +1,393 @@ + + + + + + + + + + + Mensajes y metodos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Mensajes y metodos +

    +
    + + + +
    +

    Definiciones

    + +

    Un mensaje es algo que yo le puedo decir a un objeto.

    + +

    Un método es una secuencia de líneas de código que tiene un nombre.

    + +

    Cuando se le envía un mensaje a un objeto, se activa un método cuyo nombre coincide con el mensaje enviado. La palabra método puede entenderse como “forma”, describe la forma en que algunos objetos responden a un determinado mensaje cuando alguien se los envía.

    + +

    P.ej. si tengo un objeto referenciado por la variable pepe, y pongo

    + +

     Smalltalk: + pepe direccion

    + +

     Wollok: + pepe.direccion()

    + +

    entonces

    + +
      +
    • estoy enviando el mensaje direccion
    • +
    • se va a activar un método llamado direccion. ¿Qué método? El que decida el method lookup
    • +
    + +

    ¿A quiénes se le pueden mandar mensajes en un método?

    + +
      +
    • A los objetos que conocidos mediante atributos
    • +
    • A los objetos que me pasan por parámetro
    • +
    • A mí mismo usando self
    • +
    • A los objetos bien conocidos (incluyendo a los literales)
    • +
    + +

    Importante no olvidar

    + +
      +
    • Los mensajes los entienden los objetos
    • +
    • Si a un objeto que entiende el mensaje m le envio el mensaje m entonces se va a activar el método m para ese objeto
    • +
    • Cuando en un método dice self, es una referencia al objeto que recibió el mensaje por el cual se activó el método. +En el ejemplo, si en el método direccion dice self, entonces al hacer pepe direccion este self va a ser una referencia al objeto referenciado por pepe.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/metamodelo.html b/wiki/articles/metamodelo.html new file mode 100644 index 0000000000..68fe97ff40 --- /dev/null +++ b/wiki/articles/metamodelo.html @@ -0,0 +1,323 @@ + + + + + + + + + + + Metamodelo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Metamodelo +

    +
    + + + +
    +

    Un modelo es una descripción abstracta que describe aquello que se desea construir. Al definir un modelo uno sigue un conjunto de reglas. Por ejemplo: en un diagrama de secuencia las flechas (mensajes) entre las líneas deben darse de determinadas maneras, no pueden tener cualquier organización porque no tendría sentido. A este conjunto de reglas lo denominamos metamodelo.

    + +

    El metamodelo nos dice:

    + +
      +
    • qué tipo de abstracciones podemos usar en nuestro modelo (por ejemplo: clases)
    • +
    • qué características podemos asociarle a esas abstracciones (por ejemplo: métodos, atributos)
    • +
    • qué mecanismos tenemos para relacionar esas abstracciones entre sí (herencia, asociación)
    • +
    + +

    Al construir, si utilizamos un lenguaje de alto nivel (o sea, no assembler) ese lenguaje también tendrá la capacidad de especificar abstracciones dentro del lenguaje, como procedimientos, funciones, tipos abstractos de datos, clases, objetos, herencia, polimorfismo, aspectos, mixins, servicios, componentes, etc. Obviamente, las abstracciones que puedo construir en un lenguaje dado, dependen también de un conjunto de reglas; dicho de otra manera el lenguaje tiene su propio metamodelo.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/metaprogramacion.html b/wiki/articles/metaprogramacion.html new file mode 100644 index 0000000000..c828eb0ea4 --- /dev/null +++ b/wiki/articles/metaprogramacion.html @@ -0,0 +1,393 @@ + + + + + + + + + + + Metaprogramacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Metaprogramacion +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Concepto

    + +

    Metaprogramación es el proceso o la práctica por la cual escribimos programas que generan, manipulan o utilizan otros programas.

    + +

    Ejemplos:

    + +
      +
    • Un compilador se puede pensar como un programa que genera otro programa.
    • +
    • Un formateador de código es un programa que manipula otro programa.
    • +
    • Una herramienta como javadoc utiliza nuestro programa para generar su documentación.
    • +
    + +

    Para qué se usa la metaprogramación ?

    + +

    En general la metaprogramación se utiliza más fuertemente en el desarrollo de frameworks. Simplemente porque un framework va a resolver cierta problemática de una aplicación, pero no va a estar diseñado para ninguna en particular. Es decir, la idea de framework es que se va a poder aplicar y utilizar en diferentes dominios desconocidos para el creador del framework.

    + +

    Entonces estos frameworks van a manipular objetos, sin conocerlos de antemano.

    + +

    Ejemplos:

    + +
      +
    • ORM’s como hibernate: que van a encargarse de persistir las instancias de nuestras clases sin siquiera conocerlas de antemano.
    • +
    • Frameworks de UI: que deberán saber mostras cualquier objeto.
    • +
    • Otras herramientas: +
        +
      • javadoc: es una herramienta como el compilador de java, que lee el código fuente y genera documentación html.
      • +
      • code coverage: herramientas que miden cuánto de nuestro código es realmente ejecutado al correr los tests, y cuales lineas no.
      • +
      • analizadores de código: que evalúan nuestro código y genera métrics o miden violaciones a reglas definidas. Como el estilo de código, complejidad ciclomática, etc. Por ejemplo para java existe sonar que junto a maven automatizan y concrentran varias otras herramientas.
      • +
      +
    • +
    + +

    Modelos y metamodelos

    + +

    Así como todo programa construye un modelo para describir su dominio. El domino de un metaprograma es otro programa denominado programa objeto o base y tendrá un modelo que describe a ese programa, al que llamamos metamodelo.

    + +

    En el siguiente ejemplo, nuestro dominio contiene diferentes tipos de animales, entre ellos perros y humanos.

    + +

    El programa describe las características de los elementos del dominio utilizando (por ejemplo) clases, métodos y atributos. Entonces, el modelo contiene una clase Perro, que modela a los perros en el domino. Y el programa manipula instancias de la clase Perro.

    + +

    Un metaprograma tendrá a su vez un (meta)modelo que describe a su dominio, el programa base. Así como en el dominio hay animales concretos, los habitantes del “metadominio” (= programa base) serán los elementos del programa: por ejemplo, clases, atributos, métodos. Entonces el metamodelo deberá tener clases que permitan describir esos conceptos, por ejemplo en el metamodelo de Java encontraremos las clases Class, Method, Field. Este metamodelo describe la estructura posible de un programa Java. En otro lenguaje, ese metamodelo tendría diferentes elementos.

    + +

    Así como el programa manipula las instancias de las clases Perro o Animal, el metaprograma manipula las instancias de las clases que conforman el metamodelo (Class, Method, Field, o las que fueran).

    + +

    Los lenguajes pueden proveen herramientas de Reflection para trabajar sobre su propio metamodelo.

    + +

    Ejemplo de metaprogramación en Java: XUnit +Ejemplo de metaprogramación en Ruby: XUnit

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/method-lookup.html b/wiki/articles/method-lookup.html new file mode 100644 index 0000000000..d7d72b620d --- /dev/null +++ b/wiki/articles/method-lookup.html @@ -0,0 +1,421 @@ + + + + + + + + + + + Method lookup + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Method lookup +

    +
    + + + +
    +

    Es el mecanismo por el cual se determina para el envío de un mensaje qué método se debe ejecutar. Este mecanismo puede variar en función de la tecnología usada, la explicación que se da a continuación se basa en Smalltalk usando clases, para leer sobre este mecanismo usando prototipos ver Prototipado.

    + +

    ¿Qué pasa cuando a un objeto i instancia de la clase C se le envía un mensaje de nombre m?

    + +

    Tenemos (a efectos de entender el mecanismo porque esto lo hace internamente el ambiente) que mantener una referencia a la clase donde estamos buscando en un momento determinado.

    + +

    Al principio la clase actual es C por ser la clase a partir de la cual instanciamos al objeto receptor del mensaje que es i.

    + +

    El algoritmo es el siguiente:

    + +

    1. se busca en la clase actual un método con el nombre m

    + +

    1a. si se encuentra se ejecuta el método encontrado; se ejecuta el método en el objeto i y se terminó el method lookup

    + +

    1b. si no se encuentra y la clase actual no es Object la clase actual pasa a ser la superclase de la clase actual y se vuelve a 1.

    + +

    1c. si no se encuentra y la clase actual es Object entonces el objeto i no entiende el mensaje m

    + +

    El comportamiento por defecto en Smalltalk cuando un objeto no entiende un mensaje es lanzar un error. Esto se logra a través del envío de un mensaje llamado #doesNotUnderstand: al objeto i (el método #doesNotUnderstand: está definido en la clase Object)

    + +

    Ejemplo básico

    + +

    Si le enviamos el mensaje asUppercase al objeto 'hola' (o sea, al string 'hola') ¿qué debería pasar?

    + +

    Asumamos (porque no es así) que 'hola' es instancia de String, que String es subclase de Collection y que Collection es subclase de Object.

    + +

    Siguiendo el algorítmo de arriba a través de los pasos indicados con -

    + +

    i es 'hola'

    + +

    clase actual es String

    + +

    m es #asUppercase

    + +

    - se busca en String un método con el nombre #asUppercase

    + +

    - se encuentra el método #asUppercase en la clase String

    + +

    - se ejecuta el método #asUppercase de la clase String sobre i el objeto receptor del mensaje (o sea hola)

    + +

    Conclusión: 'hola' entiende el mensaje #asUppercase

    + +

    Ejemplo (heredando un método)

    + +

    Basándonos en el ejemplo 1, si le enviamos el mensaje isNil al objeto 'hola' (o sea, al string 'hola') ¿qué debería pasar?

    + +

    i es 'hola'

    + +

    clase actual es String

    + +

    m es #isNil

    + +

    - se busca en String un método con el nombre #isNil

    + +

    - no se encuentra el método #isNil en String y la clase actual no es Object entonces la clase actual pasa a ser Collection (la superclase de la clase actual) y se vuelve a 1.

    + +

    - se busca en Collection un método con el nombre #isNil

    + +

    - no se encuentra el método #isNil en Collection y la clase actual no es Object entonces la clase actual pasa a ser Object (la superclase de la clase actual) y se vuelve a 1.

    + +

    - se busca en Object un método con el nombre #isNil

    + +

    - se encuentra el método #isNil en la clase Object

    + +

    - se ejecuta el método #isNil de la clase Object sobre i el objeto receptor del mensaje (o sea hola)

    + +

    Conclusión: 'hola' entiende el mensaje #isNil

    + +

    Es importante entender que, independientemente de dónde se mande un determinado mensaje (por ejemplo, podría ser en un método heredado donde se mande un mensaje a self), el method lookup va a arrancar por la clase a partir de la cual se instanció el objeto. Lo único que puede alterar este mecanismo para empezar a buscar desde una clase distinta es si se mandó el mensaje a super.

    + +

    Ejemplo (no entiende el mensaje)

    + +

    Basándonos en el ejemplo 1, si le enviamos el mensaje factorial al objeto 'hola' (o sea, al string 'hola') ¿qué debería pasar?

    + +

    i es 'hola'

    + +

    clase actual es String

    + +

    m es #factorial

    + +

    - se busca en String un método con el nombre #factorial

    + +

    - no se encuentra el método #factorial en String y la clase actual no es Object entonces la clase actual pasa a ser Collection (la superclase de la clase actual) y se vuelve a 1.

    + +

    - se busca en Collection un método con el nombre #factorial

    + +

    - no se encuentra el método #factorial en Collection y la clase actual no es Object entonces la clase actual pasa a ser Object (la superclase de la clase actual) y se vuelve a 1.

    + +

    - se busca en Object un método con el nombre #factorial

    + +

    - no se encuentra y la clase actual es Object entonces el objeto i no entiende el mensaje m

    + +

    O dicho de otra forma, 'hola' no entiende el mensaje #factorial

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/method-missing.html b/wiki/articles/method-missing.html new file mode 100644 index 0000000000..d6d9b04f5f --- /dev/null +++ b/wiki/articles/method-missing.html @@ -0,0 +1,330 @@ + + + + + + + + + + + Method missing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Method missing +

    +
    + + + +
    +

    Method missing (o Does not understand en Smalltalk) es un punto de intercepción en el method lookup que ofrecen algunos lenguajes para definir código a ejecutar si el objeto receptor no entiende el mensaje recibido. Si el method lookup falla, el objeto receptor recibirá el mensaje method_missing que en Object lanza un error por no entender el mensaje, pero qué pasa si redefinimos este mensaje?

    + +

    Poder interceptar el method lookup de esta forma y redefinir lo que debería suceder en caso de que un objeto de la clase A no entienda el mensaje recibido es una herramienta muy poderosa ya que permite armar definiciones genéricas para cualquier mensaje (o para un amplio conjunto que nosotros estemos interesados).

    + +

    Algunos ejemplos de uso:

    + +
      +
    • en ocasiones es útil usar un objeto que ante cualquier mensaje no haga nada, pero tampoco explote (un deaf object), en este caso la implementación es trivial ya que un method_missing vacío hará que la interfaz de nuestro objeto sea infinita.
    • +
    • se puede usar para hacer APIs que, en base a algún patrón del nombre del mensaje, se pueda ejecutar una lógica particular. Por ejemplo, en Ruby on Rails se pueden consultar todos los objetos persistidos que cumplan un cierto criterio en base a los atributos de los mismos con un mensaje a la clase find_by que recibe un diccionario:
    • +
    + +

    Person.find_by(user_name: user_name, password: password)

    + +

    Pero también se puede usar de la siguiente forma:

    + +

    Person.find_by_user_name_and_password(user_name, password)

    + +
      +
    • si se quiere implementar un decorator para lo cual el decorador tendrá muchos métodos que sean sólo delegar en el decorado el mismo mensaje que recibió, podría resolverse el dispatch de forma genérica en el method_missing y sólo definir aquellos métodos en los cuales sí existe alguna lógica propia que aportar.
    • +
    + +

    Supongamos que queremos hacer el method_missing para nuestro decorador, podría ser algo como:

    + +

    def method_missing(symbol, *args, &block) +   if @decorado.responds_to?(symbol) +     @decorado.send(symbol, *args) +   else +     super +   end +end

    + +

    De esa forma si el objeto decorado entiende el mensaje, se lo mandará, de lo contrario ejecutará method_missing de la superclase.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/metodos-de-clase-para-crear-objetos-inicializados.html b/wiki/articles/metodos-de-clase-para-crear-objetos-inicializados.html new file mode 100644 index 0000000000..a763f78a09 --- /dev/null +++ b/wiki/articles/metodos-de-clase-para-crear-objetos-inicializados.html @@ -0,0 +1,387 @@ + + + + + + + + + + + Metodos de clase para crear objetos inicializados + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Metodos de clase para crear objetos inicializados +

    +
    + + + +
    +

    A veces, es necesario inicializar alguna/s de la/s variable/s de un objeto, con objetos fijos, o con objetos que hay que pasarle apenas se crea el objeto.

    + +

    Para esto hacemos un método al que por convención se lo llama initialize, y le enviamos el mensaje correspondiente a cada objeto que creamos desde el workspace. Por ejemplo

    + +

      #Camion +  initialize +     viajes := Set new. +     desgasteDeLasRuedas := 0. +     puedeViajar := true. +  chofer := unFercho +     chofer := unFercho

    + +

      "... en el workspace ..." +  elReyDelAcceso := Camion new. +  elReyDelAcceso initialize. +  elReyDelAcceso conductor: cacho. +  "cacho lo tenía creado más arriba en el workspace"

    + +

    Ahora bien, serían muy felices dos cosas

    + +
      +
    • ahorrarme el decirle “inicialize” a cada Camion que creo
    • +
    • poder pasarle el chofer al camión en el momento de crearlo,
    • +
    + +

    Con la lazy inicialization, puedo lograr lo primero pero no lo segundo.

    + +

    Una forma de lograr las dos cosas es definir un método de clase que tiene como objetivo crear un objeto ya configurado y listo para usar.

    + +

    ¿Cómo hacemos? Fácil

    + +

      #Camion class +  nuevoConducidoPor: unFercho +      | camionNuevo | +      camionNuevo := self new. +      camionNuevo initialize. +      camionNuevo chofer: unFercho. +      ^camionNuevo

    + +

    Vemos que el método

    + +
      +
    • crea un camión nuevo enviándose un mensaje a self, que es la clase Camion.
    • +
    • lo configura
    • +
    • lo devuelve (muuuuy importante)
    • +
    + +

    En el workspace nos queda

    + +

      elReyDelAcceso := Camion nuevoConducidoPor: cacho.

    + +

    ¿qué ganamos?

    + +
      +
    • que no nos olvidamos de inicializar ningún camión
    • +
    • que el workspace queda más compacto, importante para los workspace de TP que pueden implicar la creación de muchos objetos.
    • +
    • que si le digo a la gente que va a usar los camiones que los cree siempre diciéndole a la clase lo que yo les indico, todos los camiones van a nacer ya con chofer asignado, lo que tal vez es necesario para que los camiones no den errores después.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/min--y-max-.html b/wiki/articles/min--y-max-.html new file mode 100644 index 0000000000..271bc1831c --- /dev/null +++ b/wiki/articles/min--y-max-.html @@ -0,0 +1,327 @@ + + + + + + + + + + + Min y max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Min y max +

    +
    + + + +
    +

    ejemplo: un remis cobra 2 pesos por kilómetro, mínimo 5 pesos. Tengo que escribir el método precioViaje: en la clase Remis. ¿Hago esto?

    + +

       precioViaje: unViaje +       | precio | +       precio := 2 * unViaje distancia. +       precio >= 5 ifTrue:[^precio] ifFalse:[^5]

    + +

    nuuuuuuu … los programadores objetosos con estilo sólo usan … min: y max:. Estos mensajes los entienden los números, reciben otro número como parámetro, y devuelven el más chico / más grande entre self y el parámetro. Pueden probar esto en un workspace

    + +

       3 min: 8 +   3 max: 8 +   3 min: 1 +   3 max: 1

    + +

    Entonces ¿cómo queda el precioViaje:? Lo que tengo que devolver es el máximo entre 5 y el resultado de la cuenta (piénsenlo …), entonces queda así

    + +

       precioViaje: unViaje +       ^5 max: (2 * unViaje distancia)

    + +

    bel-leza

    + +

    Para practicar, hagamos que a un remis le pueda preguntar

    + +
      +
    • la cantidad de pasajeros legal, que es la que tiene, pero nunca puede ser más de 5. O sea, si en realidad lleva 7 personas, la cantidad legal es 5.
    • +
    • el consumo por combustible, que es 1 litro cada 8 km, mínimo 2 litros.
    • +
    + +

    Los remises entienden distancia y cantPasajeros

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/mixins.html b/wiki/articles/mixins.html new file mode 100644 index 0000000000..c798722bc7 --- /dev/null +++ b/wiki/articles/mixins.html @@ -0,0 +1,366 @@ + + + + + + + + + + + Mixins + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Mixins +

    +
    + + + +
    +

    Similares a los Traits, estas construcciones, que proveen la implementación de un conjunto de métodos, pueden ser combinadas y conforman un mecanismo de compartición de código complementario a las clases. Su principal diferencia con los Traits es que pueden definir y acceder a variables y su combinación no producen conflictos, ya que estos se resuelven automáticamente por un mecanismo de linearization.

    + +

    Los Mixins tienen implementaciones en varios de los lenguajes más modernos, como ser Ruby, Scala (en el lenguaje se les dice trait, pero son mixins), Python y Groovy.

    + +

    Gracias al mecanismo de linearization, los mixins resuelven el problema del rombo o diamante presente en la herencia múltiple, definiendo una precedencia entre los mixins que componen una clase dependiendo del orden de composición, es decir, si la clase C se compone de los mixins {A, B}, se tomarán los métodos de B en los casos en los que se presenten conflictos. Como consecuencia de esta decisión de diseño de los mixins, resultará diferente la composición {A, B} que {B, A}.

    + +

    Descripción

    + +

    Un Mix-In es una subclase abstractas: como una subclase que no está ligada a ninguna superclase. Se puede “aplicar” a cualquier superclase (can be “mixed-in”)

    + +

    Se puede ver como una refactorización de la herencia hacia una “chain of resposibilities”.

    + +
      +
    • En una herencia normal, cada clase (nodo) de la cadena, conoce exactamente a su siguiente (superclase). Por lo que la cadena es “rígida”.
    • +
    • Un mixin es un nodo que no conoce está atado al siguiente en la cadena, aunque puede usarlo (como en el chain of resposibilities de GoF). Por lo que se puede reutilizar y aplicar a diferentes “cadenas”.
    • +
    + +

    Concepto

    + +
      +
    • Cumplen el rol de la reutilización que cumple una clase, sin tener el rol de ser “generadores de instancias”.
    • +
    • Representan o modelan un cierto “feature” que puede ser reutilizado y aplicado a varias clases en diferentes jerarquías
    • +
    • Generalmente se utilizan para roles o características de una clase como Observable.
    • +
    • No presentan el problema del diamante de la herencia múltiple, ya que el orden de composición actúa como técnica de resolución implícita. Es decir el primer mixin declarado que entienda el mensaje lo va a responder.
    • +
    + +

    Clasificación

    + +
      +
    • Completo: cuando todo su comportamiento depende de sí mismo y no de un comportamiento externo (definido en la clase sobre la que se aplica).
    • +
    • Parcial: cuando su comportamiento usa/delega/depende de otro comportamiento de la clase sobre la que se aplica.
    • +
    + +

    Ejemplos

    + + + +

    En Scala es posible, no sólo aplicar el mixin estáticamente en la jerarquía, sino también al instanciar un objeto particular. En este ejemplo vemos una alternativa al decorator basado en mixins: Stackable Trait Pattern

    + +

    Papers

    + +

    Mixin-Based Inheritance

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/modelando-objetos---responsabilidades-y-delegacion.html b/wiki/articles/modelando-objetos---responsabilidades-y-delegacion.html new file mode 100644 index 0000000000..1bb5f8c328 --- /dev/null +++ b/wiki/articles/modelando-objetos---responsabilidades-y-delegacion.html @@ -0,0 +1,408 @@ + + + + + + + + + + + Modelando objetos responsabilidades y delegacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Modelando objetos responsabilidades y delegacion +

    +
    + + + +
    +

    A la hora de querer resolver un problema parados en el paradigma de objetos, hay ciertas cuestiones básicas que debemos tener en cuenta para triunfar y ser felices :). De todas aquellas, vamos a nombrar principalmente a las que se destacan en este paradigma en contraposición de los otros que conocemos (lógico, funcional y estructurado o procedural).

    + +

    Objeto

    + +

    Cuando programamos en objetos, debemos pensar en objetos. Solo tenemos objetos a los que mandarles mensajes para que nos resuelvan nuestro problema. A su vez, a veces es conveniente tener muchos objetos, para poder partir el problema en varias partes más pequeñas y que sea sencillo resolver cada parte por separado. Cada un de esos otros objetos van a tener una responsabilidad.

    + +

    Responsabilidad

    + +

    Es aquello que hace un objeto. Aquello que nosotros queremos que haga. Si tenemos un solo objeto que hace demasiadas o todas las tareas de nuestro programa (a.k.a. God Object), probablemente sea complicado que nuestro programa cambie y resuelva nuevos problemas. Va a ser complicado saber si funciona correctamente (testearlo). Va a ser complicado arreglar los errores que tenga!! (si es que los tiene). Si tenemos varios objetos con menos responsabilidades cada uno (mas chiquitos), va a ser más sencillo intercambiarlos usando polimorfismo, reutilizar partes de código en otras partes de nuestro programa, evitar repeticiones de lógica… Por esas razones, es que queremos que nuestros objetos tengan bien repartidas las responsabilidades entre ellos.

    + +

    Delegacion y Colaboración

    + +

    Cuando tenemos bien repartidas las responsabilidades entre nuestros objetos, probablemente hayamos encontrado varios objetos. Ahora, cada uno resuelve su problema ¿Cómo los pegamos? Los objetos se conocen a través de referencias, y así pueden mandarse mensajes. Cuando un objeto resuelve parte de un problema y le pasa otra parte del problema a algun objeto que conozca, hablamos que ambos objetos estan colaborando. Así, cuando un objeto le encarga toooda la tarea a resolver a otro objeto, decimos que este delega la responsabilidad.

    + +

    Ejemplo

    + +

    Supongamos que queremos que un tanque que dispara misiles térmicos le dispare a otro tanque. El daño que hace un misil térmico es 10 veces la cantidad de ocupantes del tanque al que es disparado. El tanque enemigo tiene una coraza que va decrementando a medida que recibe daño (el mismo es destruído cuando la coraza llega a 0) y debe ser manejado por 3 personas. Una solución bien delegada podría ser:

    + +
    object tanqueDeMisiles {
    +  var misil = misilTermico
    +  method dispararA(otroTanque) {
    +    otroTanque.recibirDanio(misil.cuantoDanioPara(otroTanque))
    +  }
    +}
    +
    +object tanqueEnemigo {
    +  var coraza = 100
    +  method recibirDanio(cant) {
    +    coraza = (coraza - cant).max(0)
    +  }
    +
    +  method cantidadOcupantes() {
    +    return 3
    +  }
    +}
    +
    +object misilTermico {
    +  method cuantoDanioPara(unTanque){
    +    return unTanque.cantidadOcupantes()*10
    +  }
    +}
    +
    + +

    Es particularmente importante que la forma de recibir daño esté delegada en el tanque enemigo, ya que no hay ningún motivo para que el tanque de misiles sepa de la existencia de una coraza del enemigo (mejor en términos de encapsulamiento).

    + +

    El mismo ejemplo en Smalltalk:

    + +
    #TanqueDeMisiles
    +>> dispararA: otroTanque
    +   otroTanque recibirDaño: (misil cuantoDañoPara: enemigo).
    +
    +#TanqueEnemigo
    +>> recibirDaño: cant
    +  coraza := (coraza - cant) max: 0
    +
    +>> cantidadOcupantes
    +  ^ 3
    +
    +#MisilTermico
    +>> cuantoDanioPara: unTanque
    +  ^ unTanque cantidadOcupantes * 10
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/monada.html b/wiki/articles/monada.html new file mode 100644 index 0000000000..daf2e54909 --- /dev/null +++ b/wiki/articles/monada.html @@ -0,0 +1,341 @@ + + + + + + + + + + + Monada + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Monada +

    +
    + + + +
    +

    Este artículo está en construcción.

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/no-hay-instancias-para-el-show.html b/wiki/articles/no-hay-instancias-para-el-show.html new file mode 100644 index 0000000000..0680786e4e --- /dev/null +++ b/wiki/articles/no-hay-instancias-para-el-show.html @@ -0,0 +1,384 @@ + + + + + + + + + + + No hay instancias para el Show + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + No hay instancias para el Show +

    +
    + + + +
    +

    A muchos probablemente les haya sucedido encontrarse con el error No instance for Show. +Esto, contrario a lo que muchos creen, no significa que nos quedamos sin show por falta de instancias. +Lo que significa es, en criollo, “ARRRGH, no sé mostrar esto en la consola”

    + +

    Sólo que lo dice aproximadamente así:

    + +
    <interactive>:2:1:
    +    No instance for (Show (a0 -> Bool))
    +      (maybe you haven't applied enough arguments to a function?)
    +      arising from a use of ‘print’
    +    In the first argument of ‘print’, namely ‘it’
    +    In a stmt of an interactive GHCi command: print it
    +
    + +

    Solución rápida

    + +

    La mayoría de los datos son “mostrables”. Si yo quiero mostrar un “3”, la consola lo sabe mostrar:

    + +
    Main> 3
    +3
    +
    + +

    Pero no puedo mostrar una función:

    + +
    Main> even
    +<interactive>:2:1:
    +   No instance for (Show (a0 -> Bool))
    +     (...)
    +
    + +

    Solución rápida 1

    +

    Arriba de todo en el archivo .hs escribir:

    + +
    import Text.Show.Functions
    +
    + +

    Esto hace que las funciones sean mostrables:

    + +
    Main> even
    +<function>
    +
    + +

    Solución rápida 2

    + +

    En realidad, técnicamente lo que estamos haciendo al hacer el import de Text.Show.Functions es lo mismo que agregar esto al principio de nuestro archivo:

    + +
    instance Show (a -> b) where
    +  show f = "<una función>"
    +
    + +

    Esto hace que las funciones sean mostrables:

    + +
    Main> even
    +<una función>
    +
    + +

    Explicación

    + +

    Para entender más sobre el tema, se recomienda la lectura de Definiendo nuestros Tipos

    + +

    También se recomienda la lectura de Learn you a Haskell, el capítulo sobre clases de tipos

    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/nombres-de-clases.html b/wiki/articles/nombres-de-clases.html new file mode 100644 index 0000000000..24743f1006 --- /dev/null +++ b/wiki/articles/nombres-de-clases.html @@ -0,0 +1,307 @@ + + + + + + + + + + + Nombres de clases + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Nombres de clases +

    +
    + + + +
    +

    ¿Singular o plural?

    + +

    Partimos de que una clase representa un concepto, y cada instancia de esa clase va a representar a un ente que corresponde a ese concepto.

    + +

    P.ej. la clase Golondrina representa al concepto de “ser golondrina”, cada instancia representa a una golondrina (un ente de la vida real que en el contexto del software que estoy construyendo corresponde al concepto Golondrina).

    + +

    El nombre de una clase debe referirse a lo que va a representar una instancia cualquiera. Si le pongo Golondrina a una clase, es porque cada instancia va a representar a una golondrina.

    + +

    Entonces, si p.ej. a una clase le pongo Camiones, ¿qué quiere decir?. Que cada instancia va a representar a un conjunto de camiones. Si quiero que cada instancia represente a un camión, entonces está mal ponerle plural al nombre de la clase, en este caso debería llamarse Camion.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/normalizacion-en-objetos.html b/wiki/articles/normalizacion-en-objetos.html new file mode 100644 index 0000000000..f32279ede0 --- /dev/null +++ b/wiki/articles/normalizacion-en-objetos.html @@ -0,0 +1,522 @@ + + + + + + + + + + + Normalizacion en objetos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Normalizacion en objetos +

    +
    + + + +
    +

    Objetivo

    + +

    El proceso de normalización se origina con el esquema relacional y ha sido ampliamente estudiado y difundido, ya que los RDBMS surgieron como una alternativa a los motores de bases de datos jerárquicos que permitían redundancia de la información y tenían problemas de consistencia, lo que llevaba a tener datos faltantes o duplicados.

    + +

    Si bien el modelo de objetos tiene algunas características diferenciales respecto al relacional, podemos encontrar decisiones que tienen que ver con la aplicación (o no) de la normalización y el almacenamiento redundante de la información.

    + +

    Ejemplo

    + +

    Consideraremos como ejemplo un dominio conocido: la relación many-to-many entre alumnos y cursos. Un alumno se inscribe en varios cursos y en cada curso tenemos muchos alumnos.

    + +

    + +

    + +

    Recordemos qué busca la normalización

    + +
      +
    • Evitar redundancias
    • +
    • Evitar inconsistencias: no quiero que un profesor renuncie y el curso quede apuntando a un profesor inexistente
    • +
    • Reducir el impacto de los cambios en los datos: si cargué mal la información de un profesor, debería actualizarlo en un solo lugar
    • +
    + +

    Primer modelo posible

    + +

    El alumno tiene como atributos nombre, y los cursos. El curso tiene el nombre del profesor (un String) y los alumnos que participan.

    + +

    Aplicando reglas de normalización (o no)

    + +

    Campos calculados

    + +

    Es una técnica usual en muchas tecnologías, en objetos también. Podríamos pensar ejemplos:

    + +
      +
    • la cantidad de alumnos de un curso
    • +
    • la cantidad de alumnos de un curso en condiciones de firmar
    • +
    • el promedio de notas de un alumno en un curso
    • +
    + +

    se trata de atributos que pueden calcularse pero que por algún motivo elegimos almacenarlos como dato, ya sea

    + +

    1) porque es conveniente cuando lo migramos a un esquema relacional, para facilitar las consultas posteriores, ej: conocer los cursos con más de 40 alumnos sería

    + +
    +
    +
    +      select *
    +  from cursos c
    + where c.cantidad_alumnos > 40
    +
    +    
    +
    +
    + +

    Mientras que si no estuviera ese dato necesitaríamos hacer un join con la tabla de relación cursos-alumnos + el correspondiente count.

    + +

    2) porque queremos mejorar la performance, aun en objetos, en especial cuando es más frecuente consultar la cantidad de alumnos en un curso vs. inscribir un alumno a un curso

    + +

    Campos calculados vs. datos del negocio no siempre calculables

    + +

    Si necesitamos saber cuántos inscriptos hubo al comienzo del cuatrimestre, debemos tener en cuenta que

    + +
      +
    • el campo se puede calcular en un momento t0
    • +
    • pero una vez pasado ese momento, el cálculo puede perderse (por ejemplo porque algún alumno abandona la cursada o se cambia de curso)
    • +
    + +

    Este requerimiento no tiene nada que ver con la normalización, porque no hay redundancia, en ese caso lo que tenemos que hacer es crear un atributo en el Curso…

    + +

    + +

    + +

    1FN: Aplicabilidad en objetos

    + +

    La primera forma normal nos pide que

    + +
      +
    • no haya filas duplicadas, y esto se da mediante la identificación de claves candidatas
    • +
    • no haya campos repetitivos / atributos multivaluados
    • +
    + +

    Aquí vemos que las restricciones de primera forma normal no aplican para el modelo de objetos, dado que no existe el concepto de relación o tabla como punto de concentración de todos los alumnos. Cada alumno que se crea forma parte del ambiente mientras tenga una referencia, y no hay riesgo de “filas duplicadas” ni necesidad de usar una clave candidata, ya que cada objeto nuevo tiene su propia identidad respecto a los demás objetos.

    + +

    Por otra parte, un alumno puede tener una colección de cursos y cada curso una colección de alumnos (o un mapa alumno-notas). La restricción de no tener atributos multivaluados, o un atributo subdivisible en una estructura interna no aplica tampoco al modelo de objetos, donde la referencia es a cualquier tipo de objeto, incluido una colección.

    + +

    2FN y 3FN en objetos

    + +

    Tanto 2 como 3FN buscan que todo determinante sea clave candidata, o explicado en una manera más simple, no haya dependencias de ningún atributo con otro atributo

    + +
      +
    • que forme parte de la clave principal
    • +
    • que no forme parte de la clave principal
    • +
    + +

    Dado que en objetos no utilizamos el concepto de clave primaria, no tiene sentido discriminar cada caso en particular. Lo que sí podemos revisar es el ejemplo nuevamente, donde en el objeto Curso se registra la información sobre el legajoDocente (un entero) y el nombreDocente (un String).

    + +

    + +

    + +

    pasa a…

    + +

    + +

    + +

    Nosotros podemos llegar a encontrar una abstracción Docente de dos maneras posibles:

    + +
      +
    • aplicando la lógica de normalización, donde vemos que existe una dependencia funcional entre el nombre del docente y su legajo (sólo que el legajo y el nombre forman parte de la abstracción Docente y la forma de normalizarlo implica generar una referencia del curso hacia el objeto Docente)
    • +
    • o bien mucho antes, cuando necesitamos la abstracción Docente, porque es necesario agregarle comportamiento
    • +
    + +

    El proceso de normalización de entidades en el esquema relacional surge naturalmente como un proceso de generación de abstracciones posibles en el modelo de objetos.

    + +

    Por último, podríamos decidir que nuestro objeto Curso tuviera los atributos docente (una referencia a un objeto Docente), legajoDocente y nombreDocente por dos motivos:

    + +
      +
    • uno de negocio, si como en el caso anterior necesitáramos almacenar la información del docente en el momento de tomar el curso
    • +
    • para mejorar la performance, en ese caso introducimos una redundancia desnormalizando la información del curso. Eso permite que podamos obtener la información de un curso sin necesidad de navegar hacia otras entidades (dejando la referencia al docente en modo LAZY), algo que todo diseñador debe contemplar para los casos de uso que el negocio exige.
    • +
    + +

    Redundancias por problemas de navegabilidad

    + +

    El modelo relacional es sumamente flexible, en una relación many-to-many Alumno-Curso, podemos navegar la relación partiendo desde el curso o bien desde el alumno. En cambio, si en el modelo de objetos necesitamos resolver estos requerimientos

    + +
      +
    • saber qué alumnos del curso de Diseño aprobaron el primer parcial
    • +
    • saber en cuántos cursos está anotado un alumno de lunes a viernes
    • +
    + +

    Es mucho más fácil encarar estos objetivos si la relación de asociación entre Alumno y Curso es bidireccional, es decir que un alumno conoce la lista de cursos en los que está inscripto y un curso conoce la lista de alumnos que forman parte.

    + +

    Resumen

    + +

    En el modelo de objetos podemos aplicar ciertas reglas de normalización o redundancia, generando referencias hacia nuevas entidades o bien duplicando la información de un objeto en otro.

    + +

    Diferencias entre el modelo relacional y el de objetos

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Modelo relacionalObjetos
    Elimina duplicados mediante la primary keyTrabaja con identidad, no necesita claves naturales ni subrogadas
    No permite atributos multivaluadosPermite referenciar a cualquier tipo de objeto, incluido conjuntos y mapas
    Es un modelo flexible para navegar en cualquier direcciónLas referencias tienen una sola dirección, para tener una relación bidireccional es necesario utilizar otra referencia
    Puedo manipular los datos, los triggers o constraints me permiten asegurar la consistencia de los datosNo accedo directamente a los datos sino que envío mensajes, y los métodos permiten asegurar la consistencia del estado de cada objeto
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/notacion-point-free.html b/wiki/articles/notacion-point-free.html new file mode 100644 index 0000000000..4d8b6c1fcc --- /dev/null +++ b/wiki/articles/notacion-point-free.html @@ -0,0 +1,406 @@ + + + + + + + + + + + Notacion point free + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Notacion point free +

    +
    + + + +
    +

    A veces, como consecuencia de definir solamente en términos de Aplicación Parcial y/o Composición de funciones, escribir explícitamente los parámetros de la misma se vuelve redundante.

    + +

    Por ejemplo, se podría escribir

    + +

    esMultiploDe a b = ((==0).( `mod` a)) b 

    + +

    Sin embargo, lo que está dentro del paréntesis principal ya es una función que hace lo que queremos, con el tipo adecuado. Por lo que puede reescribirse de la siguiente manera:

    + +

    esMultiploDe a = (==0).( `mod` a)

    + +

    Lo cual se conoce como notación point-free, la cual es interesante porque pone nos permite concentrarnos en la combinación de las funciones en lugar del pasaje de paramétro, subiendo así nuestro nivel de abstracción.

    + +

    Al principio puede generar cierta confusión sobre la pregunta ¿cuantos parámetros recibe la función?. Así que analicemos algunos casos concretos.

    + +

    Una reglita básica

    + +

    La regla es que una función como esa tiene tantos parámetros como la suma entre:

    + +
      +
    • Los parámetros que aparecen a la izquierda del igual.
    • +
    • Los parámetros que “le faltan” a la expresión a la derecha del igual.
    • +
    + +

    Analizando el caso anterior vemos:

    + +
      +
    • Un parámetro a la izquierda del igual: a. (Esta parte es la más directa.)
    • +
    • La expresión de la derecha es una composición y por lo tanto una función a->b entonces le falta un parámetro.
    • +
    • En total la función recibe dos parámetros.
    • +
    + +

    Analizando un poco más los tipos

    + +

    Para no confundirse, en la forma más tradicional de escribir funciones a la expresión a la derecha del igual no le falta ningún parámetro:

    + +

    siguiente x = x + 1

    + +

    Se ve claramente que x+1 es una expresión que denota un valor numérico y no una función, o dicho de otra manera “no le faltan parámetros”. En cambio sí le faltarían si uno pusiera por ejemplo (+1).

    + +

    La definición anterior es totalmente equivalente a:

    + +

    siguiente = (+1)

    + +

    Al aplicar parcialmente la función (+) :: Num a => a -> a -> a obtenemos otra función que es del tipo Num a => a -> a. Si siguiente es igual a la función (+1), entonces su tipo es el mismo que el de (+1).

    + +

    En general lo más común es ver funciones que sólo les falta el último parámetro, como en el caso de esMultiploDe, ya que está definida en función de una composición. No sería correcto definirla de esta forma a pesar de que ambos parámetros vayan en ese orden “aplicados al final”:

    + +

    esMultiploDe = (==0).flip mod

    + +

    Como no coincide la imagen de la función flip mod

    + +

    flip mod :: Integral c => c -> c -> c

    + +

    con el dominio de (==0)

    + +

    (==0) :: (Eq a, Num a) => a -> Bool

    + +

    La composición de estas dos funciones no es correcta (de hecho esa expresión tipa, pero no lo van a poder usar porque el tipo de esMultiploDe requeriría un único argumento que sea a la vez una función y un número equiparable… y como que no tiene mucho sentido)

    + +

    Este otro ejemplo sí sería correcto:

    + +

    resto = flip mod

    + +

    El tipo de la función resto es el mismo que el de la función flip mod que ya mostramos antes.

    + +

    Pros y Cons de la notación point-free

    + +

    A favor de usar la notación point-free es que nos fuerza a dejar de pensar en función de la aplicación y los valores con los que estamos acostumbrados a trabajar, teniendo que pensar en definir funciones como equivalencia de otras funciones combinadas. El paradigma funcional se basa en la idea de combinar funciones, ellas son las divas de esta forma de pensar la programación, por eso cuando definimos funciones como composición de otras funciones y/o a la aplicación parcial de las mismas con estilo point-free, el código resultante es más limpio :)

    + +

    La notación point-free puede llevar a ofuscar el código cuando se usa malintencionadamente. Al combinar funciones puede que se vuelva más complicado inferir mentalmente el tipo de una expresión ya que cuesta más deducir la cantidad de parámetros necesarios para que la función definida se reduzca a un valor concreto mediante la aplicación.

    + +

    Otro problema que podría surgir dada una función compleja escrita de esta forma es que al intentar introducir un cambio menor de funcionalidad en la misma haya que hacer un cambio radical en el código, sin embargo para el nivel de paradigmas esto no debería suceder.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/npm-dependencias.html b/wiki/articles/npm-dependencias.html new file mode 100644 index 0000000000..e68cc8552e --- /dev/null +++ b/wiki/articles/npm-dependencias.html @@ -0,0 +1,503 @@ + + + + + + + + + + + Manejo de dependencias con NPM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Manejo de dependencias con NPM +

    +
    + + + + + +
    +

    Versionado semántico

    + +

    Recordemos que todo componente tiene una versión compuesta por tres números:

    + +
      +
    • major
    • +
    • minor
    • +
    • patch
    • +
    + +

    Ejemplo: el componente “typescript” tiene la versión “3.6.3”, donde 3 es el major number, 6 el minor y finalmente 3 es el patch.

    + +

    Para respetar el versionado semántico, al liberar una nueva versión tenemos que indicar qué es lo que trae ese nuevo componente:

    + +
      +
    • si soluciona bugs, debería incrementar el patch: el componente “typescript” pasaría a tener la versión “3.6.4”
    • +
    • si trae nuevos features o funcionalidades que no rompen la retrocompatibilidad, debería incrementar el minor a “3.7.0”
    • +
    • si trae nuevas funcionalidades que rompen la retrocompatibilidad (ej. métodos o clases que dejaron de existir, o tienen diferente cantidad de parámetros), deberíamos incrementar la major a “4.0.0”
    • +
    + +

    Dependencias de un proyecto con NPM

    + +

    package.json

    + +

    El Node Package Manager (NPM) almacena las dependencias de nuestro proyecto (entre otras configuraciones) en el archivo package.json, por ejemplo:

    + +
    +
    +
    +        "dependencies": {
    +    "@angular/animations": "^8.2.7",
    +    "@angular/common": "^8.2.7",
    +    "@angular/compiler": "^8.2.7",
    +    "@angular/core": "^8.2.7",
    +  },
    +  "devDependencies": {
    +    "@angular-devkit/build-angular": "^0.803.5",
    +    "@angular/cli": "~8.3.5",
    +    "@angular/compiler-cli": "^8.2.7",
    +    "@angular/language-service": "^8.2.7",
    +    "typescript": "~3.6.3"
    +  }
    +
    +    
    +
    +
    + +

    Por ejemplo, “~3.6.3” implica que podemos subir hasta una versión minor (3.7.x), pero no más (no a la 3.8.1 por ejemplo). El modificador “^8.2.7”, implica que podemos subir todas las versiones minor y patch que necesitemos, pero no actualizaremos la versión major a “9.0.0” por ejemplo.

    + +

    Para más información pueden leer el componente de node que trabaja el versionado semántico.

    + +

    package-lock.json

    + +

    Mientras que el package.json permite configurar las dependencias para un rango de versiones posibles, el package-lock.json es la foto de las dependencias exactas que se descargaron en tu máquina, incluyendo las dependencias indirectas.

    + +

    Esto permite que todos los desarrolladores (y especialmente el CI) puedan replicar el mismo entorno y que las versiones que instalamos no dependa del momento en el que hacemos npm install.

    + +

    Primera instalación con npm install

    + +

    La primera vez que descargamos un proyecto, debemos descargar las dependencias, para eso debemos ejecutar

    + +
    +
    +
    +      npm install
    +
    +    
    +
    +
    + +

    Si existe el archivo package-lock.json, npm partirá de esa definición para ir a buscar las dependencias y bajarlas a nuestro directorio node_modules. Si no existe el archivo package-lock.json, entonces se basará en las definiciones del package.json para buscar las últimas versiones posibles de cada uno de los componentes.

    + +

    ¿Tengo que versionar el package-json? (subirlo a git)

    + +

    TL;DR .

    + +

    La justificación es que de esa manera estaremos seguros de que todos los que trabajamos en el proyecto tengamos las mismas dependencias.

    + +

    Actualizando nuestras dependencias

    + +

    Para mantener al día las dependencias de nuestros ejemplos, tenemos dos opciones:

    + +

    Subir las versiones minor - npm update

    + +

    Podemos detectar si hay nuevas versiones minor que no rompan la retrocompatibilidad escribiendo en nuestra consola o git bash:

    + +
    +
    +
    +      npm outdated
    +
    +    
    +
    +
    + +

    O directamente podemos escribir:

    + +
    +
    +
    +      npm update
    +
    +    
    +
    +
    + +

    Al ejecutar este comando:

    + +
      +
    • se actualiza el package-lock.json
    • +
    • y también en el directorio node_modules descargamos los paquetes con el código que vamos a utilizar
    • +
    + +

    + node_modules_meme +

    + +

    Subir las versiones major (con coraje)

    + +

    Si estás seguro que vas a poder seguir manteniendo estable tu conjunto de dependencias, podés trabajar con npm-check-updates. Lo instalás globalmente la primera vez:

    + +
    +
    +
    +      npm install -g npm-check-updates
    +
    +    
    +
    +
    + +

    Y luego lo ejecutás

    + +
    +
    +
    +      ncu -u
    +
    +    
    +
    +
    + +

    Esto te va actualizar las versiones de tu package.json tratando de subir a la mayor versión posible. Luego podés correr npm update (o bien npm install si te bajaste el proyecto la primera vez)

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/objective-c.html b/wiki/articles/objective-c.html new file mode 100644 index 0000000000..4aa9b20b2a --- /dev/null +++ b/wiki/articles/objective-c.html @@ -0,0 +1,326 @@ + + + + + + + + + + + Objective c + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Objective c +

    +
    + + + +
    +

    Sobre el lenguaje

    + + + +

    Herramientas basadas en Objective C:

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/observer-en-pharo-smalltalk.html b/wiki/articles/observer-en-pharo-smalltalk.html new file mode 100644 index 0000000000..5dc473d786 --- /dev/null +++ b/wiki/articles/observer-en-pharo-smalltalk.html @@ -0,0 +1,329 @@ + + + + + + + + + + + Observer en pharo smalltalk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Observer en pharo smalltalk +

    +
    + + + +
    +

    Resumen

    + +

    El mecanismo de observer es así:

    + +
      +
    • Hay un observador (que entiende el mensaje update:, y hay que implementarlo)
    • +
    • Hay un observado (que entiende los mensajes changed: y addDependent:, que no hay que implementar pero sí usar)
    • +
    + +

    Inicialización

    + +

    Al inicializar todo (antes de que empiece a funcionar) tenés que hacer:

    + +

    observado addDependent: observador.

    + +

    Uso

    + +

    Después, el observado necesita avisar que él mismo cambió, y eso lo hace con:

    + +

    self changed: #variableQueCambió

    + +

    Pharo mágicamente le va a mandar el mensaje update: #variableQueCambio a todos sus observadores. Entonces, en cada observador tenés que definir el método:

    + +

    update: nombreDeLoQueCambio +   "acá hago lo que sea que quiera hacer el observer."

    + +

    Algo común para hacer ahí es chequear si me interesa ese nombreDeLoQueCambio, ó bien hacerle preguntas a mi observado (que me guardé de antemano).

    + +

    Diagrama de Clases

    + +

    ObserverPharo.png

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/oo-objetos-factory.html b/wiki/articles/oo-objetos-factory.html new file mode 100644 index 0000000000..179958d6e4 --- /dev/null +++ b/wiki/articles/oo-objetos-factory.html @@ -0,0 +1,551 @@ + + + + + + + + + + + Objetos factory - instanciando objetos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Objetos factory - instanciando objetos +

    +
    + + + + + +
    +

    Introducción

    + +

    Instanciar objetos no siempre resulta fácil, especialmente en los tests, cuando debemos tener en cuenta:

    + +
      +
    • valores por defecto para esa clase de equivalencia
    • +
    • configuraciones para algunos tests específicos
    • +
    • tratando siempre de que sea fácil de usar y no repetir código
    • +
    + +

    Por ejemplo, necesitamos definir una computadora que tiene 16 GB de RAM y un disco HDD de 2048, con mouse, en base a esta definición:

    + +
    +
    +
    +      class SSD {
    +  method precio() = 500
    +  method estaCopado() = true
    +}
    +
    +class HDD {
    +  var property tamanio = 1024   // expresado en GB
    +  
    +  method precio() = if (tamanio > 1024) 400 else 250
    +  method estaCopado() = tamanio > 1024
    +}
    +
    +class Memoria {
    +  var property tamanio          // expresado en GB
    +  
    +  method precio() = tamanio / 10
    +  method estaCopada() = tamanio > 16
    +}
    +
    +class Computadora {
    +  var memoria
    +  var disco = new HDD()
    +  var mouse = true
    +
    +  method precio() = memoria.precio() + disco.precio() + 1000
    +  method estaCopada() = memoria.estaCopada() || disco.estaCopado()
    +}
    +
    +    
    +
    +
    + +

    Clases de equivalencia para el precio

    + +

    Las clases de equivalencia para el precio se forman en base a diferentes configuraciones de computadoras

    + +
      +
    • ssd, no importa la memoria
    • +
    • hdd de más de 1TB, no importa la memoria
    • +
    • hdd de 1TB, no importa la memoria
    • +
    • hdd de menos de 1TB, no importa la memoria
    • +
    + +

    La presencia o no del mouse no juega ningún papel, y realmente tampoco la memoria que calcula siempre el mismo valor.

    + +

    Clases de equivalencia para estaCopada

    + +

    En cambio, las clases de equivalencia que configuran a una computadora copada son:

    + +
      +
    • computadora con ssd, no importa la memoria (copada)
    • +
    • computadora con hdd de más de 1TB, no importa la memoria (copada)
    • +
    • computadora con hdd de 1TB, memoria de 16 (no copada - caso borde en ambas configuraciones)
    • +
    • computadora con menos de 1TB, memoria más de 16 (copada)
    • +
    • computadora con menos de 1TB, memoria de menos de 16 (no copada)
    • +
    + +

    Unificando las clases de equivalencia

    + +

    Ahora vemos que si intersectamos las clases de equivalencia para precio y estaCopada, las primeras 4 de estaCopada coinciden con las de precio, por lo tanto vamos a tener que buscar estas configuraciones:

    + +
    +
    +
    +        var computadoraConSsd      = new Computadora()
    +  var computadoraConPocoHdd  = new Computadora(disco = new HDD(tamanio = 512))
    +  var computadoraComun       = new Computadora(disco = new HDD(tamanio = 1024))
    +  var computadoraConMuchoHdd = new Computadora(disco = new HDD(tamanio = 2048))
    +
    +    
    +
    +
    + +

    Dónde lo implementamos

    + +

    Las opciones son varias:

    + +
      +
    • en cada test configuramos la computadora que necesitamos: eso tiene la desventaja de que si es necesario resolver la inicialización en más pasos, se empezarán a repetir en cada uno de los tests.
    • +
    • lo ubicamos en el describe como variables, eso tiene dos desventajas: a) los tests tienen pocas variables compartidas entre sí (baja cohesión), no es fácil ver qué tests usan qué variables y la inicialización también está lejos del momento en que se prueban, y b) cada vez que corremos un test se evalúan todas las expresiones del describe, por lo que hay una penalización en performance.
    • +
    • delegar en otro objeto la inicialización de las clases de equivalencia que necesitamos, algo como
    • +
    + +
    +
    +
    +      object computadoraFixture {
    +  method computadoraConSSD() =
    +    new Computadora()
    +  
    +  method computadoraConPocoHdd() =
    +    new Computadora(disco = new HDD(tamanio = 512))
    +  
    +  method computadoraComun() =
    +    new Computadora(disco = new HDD(tamanio = 1024))
    +  
    +  method computadoraConMuchoHdd() =
    +    new Computadora(disco = new HDD(tamanio = 2048))
    +
    +}
    +
    +    
    +
    +
    + +

    Es decir, tenemos un objeto que nos ayuda a crear otros objetos, lo que podríamos llamar objetos factory (fabrican configuraciones de objetos que nosotros necesitamos frecuentemente).

    + +

    Ventajas en el mantenimiento

    + +

    El costo que pagamos es mantener una nueva abstracción, la ventaja es que si la computadora tuviera ahora una lista de dueños:

    + +
    +
    +
    +      object juan {
    +  method esCopado() = ...
    +}
    +
    +object ceci {
    +  method esCopado() = ...
    +}
    +
    +class Computadora {
    +  var memoria
    +  var disco = new HDD()
    +  var mouse = true
    +  const duenios = []
    +
    +  method precio() = memoria.precio() + disco.precio() + 1000
    +
    +  method agregarDuenio(duenio) {
    +    duenios.add(duenio)
    +  }
    +
    +  method estaCopada() =
    +    memoria.estaCopada() || disco.estaCopado() || duenios.any { duenio => duenio.esCopado() }
    +}
    +
    +    
    +
    +
    + +

    Y necesitáramos agregar en la computadora común a dos dueños, solo debemos modificar un método:

    + +
    +
    +
    +        method computadoraComun() {
    +    const compu = new Computadora(disco = new HDD(tamanio = 1024))
    +    compu.agregarDuenio(ceci)
    +    compu.agregarDuenio(juan)
    +    return compu
    +  }
    +
    +    
    +
    +
    + +

    También podríamos hacer que los otros métodos se llamen entre sí para agregar los duenios:

    + +
    +
    +
    +      method computadoraConMuchoHdd() {
    +  const compu = self.computadoraComun()
    +  compu.disco(new HDD(tamanio = 2048))
    +  return compu
    +}
    +
    +    
    +
    +
    + +

    Esto también podemos hacerlo con la variante del fixture, solo que cada vez que ejecutemos cada test se evaluarán todos los métodos.

    + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/oo-temporary-variable.html b/wiki/articles/oo-temporary-variable.html new file mode 100644 index 0000000000..b6f4833ca6 --- /dev/null +++ b/wiki/articles/oo-temporary-variable.html @@ -0,0 +1,483 @@ + + + + + + + + + + + Temporary variables + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Temporary variables +

    +
    + + + + + +
    +

    Introducción: persona instruída

    + +

    Supongamos que tenemos que conocer si Helmut es una persona instruida, esto ocurre cuando leyó más de 20 libros y conoce más de 3 idiomas.

    + +

    Tenemos esta implementación:

    + +
    object helmut {
    +  var librosLeidos = 0
    +  const idiomasQueConoce = []
    +  method leerLibro() { librosLeidos = librosLeidos + 1 }
    +  method conocerIdioma(idioma) { idiomasQueConoce.add(idioma) }
    +  method esInstruido() ...
    +}
    +
    + +

    Bad smell: temporary variable

    + +

    Es un patrón frecuente la resolución del ejemplo agregando un nuevo atributo en helmut:

    + +
    object helmut {
    +  ...
    +  var instruido = false
    +  method esInstruido() = instruido
    +}
    +
    + +

    Una solución similar puede ser definir instruido como una property, el efecto es el mismo. Esto tiene algunas desventajas:

    + +
      +
    • el problema no es tanto incorporar un nuevo atributo, sino que es un atributo que podría calcularse…
    • +
    • …y que además tiene dependencias con las otras dos variables
    • +
    + +

    Para mantener consistente el estado de Helmut, deberíamos codificar su comportamiento de la siguiente manera:

    + +
    object helmut {
    +  var librosLeidos = 0
    +  const idiomasQueConoce = []
    +  var instruido = false
    +  method leerLibro() {
    +    librosLeidos = librosLeidos + 1
    +    // sincronizo esInstruido...
    +    instruido = librosLeidos > 20 && idiomasQueConoce.size() > 3
    +  }
    +  method conocerIdioma(idioma) {
    +    idiomasQueConoce.add(idioma)
    +    // sincronizo esInstruido...
    +    instruido = librosLeidos > 20 && idiomasQueConoce.size() > 3
    +  }
    +  method esInstruido() = instruido
    +}
    +
    + +

    Por supuesto, podemos extraer un método aparte, igualmente estaremos enviando el mismo mensaje en ambos casos:

    + +
    object helmut {
    +  ...
    +  method leerLibro() {
    +    librosLeidos = librosLeidos + 1
    +    self.actualizoInstruido()
    +  }
    +  method conocerIdioma(idioma) {
    +    idiomasQueConoce.add(idioma)
    +    self.actualizoInstruido()
    +  }
    +  method actualizoInstruido() {
    +    instruido = librosLeidos > 20 && idiomasQueConoce.size() > 3
    +  }
    +  ...
    +}
    +
    + +

    Otra variante similar consiste en que el método instruido haga algo como:

    + +
    method leerLibro() {
    +  librosLeidos = librosLeidos + 1
    +  self.esInstruido()
    +}
    +method conocerIdioma(idioma) {
    +  idiomasQueConoce.add(idioma)
    +  self.esInstruido()
    +}
    +method esInstruido() {
    +  instruido = librosLeidos > 20 && idiomasQueConoce.size() > 3
    +  return instruido
    +}
    +
    + +

    lo cual agrega más desventajas:

    + +
      +
    • la variable instruido da lo mismo si es una variable de instancia (atributo) o una variable local del método esInstruido, solo se asigna para ser retornada
    • +
    • métodos que representan acciones como leer el libro o conocer idioma, llaman a una aparente pregunta (esInstruido) solo para actualizar el estado, se confunde así métodos que tienen efecto y que no lo tienen
    • +
    • si hay más atributos cuyos valores dependen de otros, puede no resultar trivial el momento de actualizar el estado del objeto sin que quede momentáneamente inconsistente (o puede resultar en errores si no respetamos el orden en que actualizamos dichos atributos)
    • +
    • En general, intentar guardarse cosas que pueden ser calculadas es un smell, conocido también como “precalcular”, término popularizado por Maese Rasta.
    • +
    + +

    Una alternativa más simple

    + +

    La alternativa más sencilla es descartar todos los atributos que pueden calcularse, de esa manera evitamos sincronizar el estado de Helmut:

    + +
    object helmut {
    +  var librosLeidos = 0
    +  const idiomasQueConoce = []
    +  method leerLibro() { librosLeidos = librosLeidos + 1 }
    +  method conocerIdioma(idioma) { idiomasQueConoce.add(idioma) }
    +  method esInstruido() = librosLeidos > 20 && idiomasQueConoce.size() > 3
    +}
    +
    + +

    Aquí vemos cómo tenemos

    + +
      +
    • métodos que producen efecto (acciones): leerLibro, conocerIdioma
    • +
    • y métodos que no tienen efecto (contestan preguntas): esInstruido
    • +
    + +

    Heurística para tener atributos que pudieran ser calculables

    + +

    En general, intentar guardarse cosas de antemano para “optimizar” es un smell. Como dijo Donald Knuth, premature optimization is the root of all evil.

    + +

    Sin embargo, sí hay ocasiones donde guardarse un resultado de antemano es aceptable:

    + +
      +
    • si el cálculo lleva tiempo (o implica acceder a recursos externos costosos, como un archivo o un servicio web)
    • +
    • si la tasa de actualización es poco frecuente pero necesitamos conocer esa información una gran cantidad de veces al día
    • +
    + +

    son señales en los que tener un cálculo como atributo es justificable, algo que es improbable que ocurra en cursos iniciales de programación OO.

    + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/orden-superior-y-diseno.html b/wiki/articles/orden-superior-y-diseno.html new file mode 100644 index 0000000000..79ba0e22fc --- /dev/null +++ b/wiki/articles/orden-superior-y-diseno.html @@ -0,0 +1,343 @@ + + + + + + + + + + + Orden superior y diseno + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Orden superior y diseno +

    +
    + + + +
    +

    Ver también Orden Superior

    + +

    Una consecuencia de implementar el pasaje de funciones como argumentos en lenguajes orientados a objetos# es que el envío de mensajes desde un objeto hacia otro ocurre en dos momentos: 

    + +

    Un objeto A envía el mensaje de orden superior a otro B, pasando por argumento un bloque de código El objeto receptor B envía un mensaje al bloque de código, que es evaluado, potencialmente, enviando mensajes a objetos que sólo A conocía.

    + +

    Es decir, mientras que en la programación imperativa el código cliente llama es aquel que llama a la biblioteca, aquí es la biblioteca quien termina llamando al código cliente, lo que se conoce como Inversión de Control (IoC).

    + +

    object PruebaIoC {

    + +

         def sumaDeInversas(valores: List[Int]) = valores.map { 1 / _ }.sum +}

    + +

    scala> PruebaIoC.sumaDeInversas( List(4,0,6) )

    + +

    java.lang.ArithmeticException: / by zero

    + +

       at PruebaIoC$$anonfun$sumaDeInversas$1.apply$mcII$sp(:8) +   at PruebaIoC$$anonfun$sumaDeInversas$1.apply(:8) +   at PruebaIoC$$anonfun$sumaDeInversas$1.apply(:8) +   at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194) +   at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194) +   at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59) +   at scala.collection.immutable.List.foreach(List.scala:45) +   at scala.collection.TraversableLike$class.map(TraversableLike.scala:194) +   at scala.collection.immutable.List.map(List.scala:45) +   at PruebaIoC$.sumaDeInversas(:8)

    + +

    …..

    + +
      +
    • Se pierde la secuencialidad
    • +
    • El control queda en manos de la biblioteca, que se constituye en un motor responsable de evaluar el código -> ganamos en declaratividad
    • +
    • el codigo puede ser evaluado de forma diferente a la planteada por el cliente, incluso de forma diferida, asincrónica o ignorado completamente
    • +
    + +

    evaluacion diferida mediante thunks

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/orden-superior.html b/wiki/articles/orden-superior.html new file mode 100644 index 0000000000..114151ee7d --- /dev/null +++ b/wiki/articles/orden-superior.html @@ -0,0 +1,461 @@ + + + + + + + + + + + Orden superior + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Orden superior +

    +
    + + + +
    +

    Generalidades

    + +

    Llamamos a una determinada operación de orden superior si la misma recibe otra operación (comportamiento) por parámetro, siendo capaz de ejecutarla internamente.

    + +

    Al usar orden superior tenemos las siguientes ventajas:

    + +
      +
    • Puedo aislar y reutilizar comportamiento común.
    • +
    • Puedo partir mi problema, separando responsabilidades, entre el código que tiene orden superior, y el comportamiento parametrizado.
    • +
    • Puedo tener un código con partes incompletas, esperando rellenarlos pasando comportamiento por parámetro, y no sólo datos.
    • +
    • ¡Puedo generar abstracciones más jugosas! Más allá de las abstracciones de orden superior que ya me proveen los lenguajes, la mayoría de los mismos me dan la posibilidad de armar mi propio comportamiento de orden superior (En la materia lo vemos en Haskell más directamente, aunque se puede también en SWI-Prolog).
    • +
    • Con abstracciones más adecuadas, con responsabilidades repartidas, y sin repetición de lógica, genero un código más expresivo (porque en general es más fácil de leer), y más declarativo (porque en general al usar orden superior oculto detalles algorítmicos)
    • +
    + +

    Paradigma Funcional

    + +

    Tanto en matemática como en informática, se definen las funciones de orden superior como funciones que reciben funciones por parámetro o bien devuelven una función como resultado.

    + +

    La función filter (en haskell y otros lenguajes funcionales) es un ejemplo común de este tipo de funciones ya que recibe por parámetro una función f y una lista y retorna una nueva lista que contiene aquellos elementos que al ser aplicados como parámetros a f devuelven verdadero. La función f debe tener entonces aridad 1 y devolver un valor booleano.

    + +

    filter :: (a -> Bool) -> [a] -> [a]

    + +

    Otras funciones comunes son map, fold, funciones de ordenamiento o búsqueda, composición de funciones (.), flip, etc (pueden consultar sus tipos en el intérprete con :t).

    + +

    Ejemplos comunes del análisis matemático que es más difícil de ver en los lenguajes de programación son la derivada y la integral (Vemos al “proceso de derivar” como una función que recibe otra función cualquiera y devuelve su derivada).

    + +

    En el Cálculo lambda no tipado todas las funciones son de orden superior. En el cálculo lambda con tipado, desde el cual la mayoría de los lenguajes funcionales se derivan, las funciones de orden superior son generalmente aquellas cuyos tipos de parámetros “contienen una o más flechitas”.

    + +

    En matemática a las funciones que retornan funciones se las conoce como operadores o functionals. Un ejemplo común es el cálculo derivativo, ya que mapea una función a otra función.

    + +

    ¿La aplicación parcial es también orden superior?

    + +

    En primer lugar, recordemos que en Haskell las funciones están currificadas. La Aplicación Parcial no es una función, lo que sí podemos analizar es la Aplicación y lo importante es qué recibe y qué devuelve, eso se ve cuando se analiza el tipo de la función. Existe una función que nos va a servir para realizar este análisis llamada $ que lo que hace es aplicarle un parámetro a una función.

    + +
    ($) :: (a -> b) -> a -> b
    +($) funcion parametro = funcion parametro
    +
    + +

    Si el primer parámetro de la función $ es una función de aridad mayor a 1 (por ejemplo, mod) y la aplicamos de la siguiente forma:

    + +

    mod $ 10

    + +

    El resultado será una función:

    + +

    mod $ 10 :: Integral a => a -> a

    + +

    La aplicación, entonces es una función de orden superior ya que recibe una función por parámetro y si la misma no queda totalmente aplicada también retorna una función.

    + +

    Paradigma Lógico

    + +

    Decimos que un predicado es de Orden Superior si este recibe como argumento una consulta a otro/s predicado/s. Algunos ejemplos son not, findall y forall.

    + +

    Hacer nuestros propios predicados de orden superior en Prolog no es tan natural como resulta en Haskell, lo cual se desprende de que los predicados y consultas no son valores, sin embargo Prolog nos permite hacerlo mediante el predicado call.

    + +

    Paradigma Estructurado

    + +

    En el paradigma estructurado, una porción de código puede alcanzar resultados algorítmicos como si fuesen obtenidos a través de funciones de orden superior, ejecutando código dinámicamente (a veces denominadas operaciones “Eval” o “Execute”) durante la evaluación. Desafortunadamente hay limitaciones al alcance del mismo:

    + +
      +
    • +

      El código en el argumento a ser ejecutado usualmente no posee tipado estático; estos lenguajes generalmente dejan relegado al tipado dinámico la determinación de la seguridad y la buena disposición del código a ser ejecutado.

      +
    • +
    • +

      El parámetro es usualmente provisto como un String, cuyo valor no puede ser conocido hasta el momento de ejecución. Este string debe ser o bien compilado durante la ejecución del programa (usando compilación just-in-time) o bien evaluado durante la interpretación, causando un overhead adicional y usualmente generando código menos eficiciente.

      +
    • +
    + +

    También pueden ser utilizadas Macros para lograr algunos de los efectos del orden superior. No obstante ello, estas macros no pueden evitar fácilmente el problema de la captura de variables; también resultan en grandes cantidades de código duplicado, el cual puede ser más difícil de optimizar para un compilador. Generalmente las Macros no son fuertemente tipadas, aunque pueden producir código fuertemente tipado.

    + +

    Si les interesa profundizar en el uso de orden superior en el lenguaje C, pueden leer el siguiente apunte realizado por ayudantes de la cátedra.

    + +

    ¿Y los objetos?

    + +

    Esta me gustó más, ahí vamos, en objetos no tiene sentido reconocer ordenes, porque lo natural es que si la operacion es el mensaje (recordar valores y operaciones), entonces tanto el receptor del mensaje como los parametros son siempre objetos.

    + +

    Entonces, estoy estudiando para el final, que tengo que entender:

    +
      +
    • que es eso de “orden”: un X que puede admitir otro X como parametro.
    • +
    • digo que reconozco dos ordenes, si eso es una característica especial que quiero remarcar, si no… lo que pasa es que no tiene sentido la distinción de órdenes en este contexto
    • +
    • para cada paradigma: si tiene sentido decir algo asi como “orden superior”, y en que casos
    • +
    • para qué uso la idea superior, en particular en funcional. Una vez que entendi eso, que herramienta que vimos de Wollok me sirve para un propósito similar. +
        +
      • En Haskell: filter (>3) unaLista
      • +
      • En Wollok: unaLista.filter({elemento => elemento > 3})
      • +
      +
    • +
    + +

    Está claro que ambos ejemplos sirven para lo mismo, pero ¿qué es lo que recibe por parámetro el filter de la solución objetosa? Es un bloque, y los bloques son objetos.

    + +

    En general no aplicamos el concepto de orden superior a los objetos porque si la definición fuera “un obeto que recibe otro objeto por parámetro” eso incluye a todos los objetos que reciban algún parámetro en algún mensaje porque…. todos son objetos. Podés pensar que todos son de orden superior, si preferís, pero no podés clasificar a los objetos en “órdenes”.

    + +

    Por otro lado me gustaría disentir con la idea de relacionar muy fuertemente a los bloques con orden superior, es cierto que estoy pasando “comportamiento” por parámetro. Pero, como decía, eso pasa muchas veces en objetos, entonces hacer una mención especial a los bloques no me parece. En algún momento nosotros mismos lo contamos en esos términos, pero bueno, evolucionamos. Igualmente esa respuesta no se consideraría errónea en un final, pero sí quiero comenzar a transmitirla de esta forma que me parece más adecuada.

    + +

    Creo que la diferencia del bloque con el resto de los objetos es la creación de comportamiento ad-hoc, para un fin específico, los uso una sola vez y no les pongo nombre. Ese efecto se asemeja a otros elementos del funcional, como ser las Expresiones lambda o la Aplicación Parcial, que me permiten armar “en el aire” funciones con esas características (fíjense que también pasa en funcional, que las expresiones lambda o la aplicación parcial son útiles para combinarlas con las funciones de orden superior).

    + +

    Volviendo al tema principal, el chiste del orden superior es que yo paso algo más complejo que un número, una lista o una estructura (functor, tupla, etc) por parámetro. Al pasar un predicado o función yo paso “comportamiento” por parámetro, el conocimiento de cómo resolver el problema ahora no se divide en datos y algoritmo, sino que la función de orden superior tiene parte del “algoritmo” y la otra parte viene por parámetro. (Nótense las comillas al usar las palabras “algoritmo” y “comportamiento” en los paradigmas declarativos.) Eso le da un poder muy piola a lo que construimos. En fin, ¿cómo llevamos eso de nuevo a objetos? Yo creo que se aprovechan beneficios similares a los del orden superior en el momento en que los objetos que interactúan (el receptor del mensaje y el parámetro) tienen dividido el comportamiento en esa forma, es decir, que el objeto receptor le pide al otro cosas que no sean solamente devolver un dato sino que tengan otra complejidad. Claro, cuando uso un bloque eso pasa siempre, y por eso es tentador establecer la relación. Pero si abrimos un poco la cancha, creo que es fácil ver que ocurre casi siempre que tengamos delegación y responsabilidades bien repartidas.

    + + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/otros-temas-interesantes-de-programacion.html b/wiki/articles/otros-temas-interesantes-de-programacion.html new file mode 100644 index 0000000000..03959c2176 --- /dev/null +++ b/wiki/articles/otros-temas-interesantes-de-programacion.html @@ -0,0 +1,342 @@ + + + + + + + + + + + Otros temas interesantes de programacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Otros temas interesantes de programacion +

    +
    + + + +
    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/pagina-principal.html b/wiki/articles/pagina-principal.html new file mode 100644 index 0000000000..12c84c5f81 --- /dev/null +++ b/wiki/articles/pagina-principal.html @@ -0,0 +1,299 @@ + + + + + + + + + + + Pagina principal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Pagina principal +

    +
    + + + +
    +

    a

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/palitos-de-queso.html b/wiki/articles/palitos-de-queso.html new file mode 100644 index 0000000000..d7c1638945 --- /dev/null +++ b/wiki/articles/palitos-de-queso.html @@ -0,0 +1,336 @@ + + + + + + + + + + + Palitos de queso + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Palitos de queso +

    +
    + + + +
    +

    + +

    Ingredientes

    + +
      +
    • 100 grs de queso rallado
    • +
    • 100 grs de pan rallado
    • +
    • 100 grs de harina
    • +
    • 100 grs de manteca
    • +
    • 1/2 cucharadita de sal
    • +
    + +

    Pasos:

    + +
      +
    1. Mezclar todo en un bol hasta que quede una masa semi dura. Agregando agua FRIA si hace falta (muy muy poquito)
    2. +
    3. Estirarla a 0.5cm de grosor y cortar en palitos de 1cm de ancho por 5cm de largo
    4. +
    5. Arrolarlos con la palma de la mano y ponerlos sobre placa enmantecadas y enharinadas
    6. +
    7. Cocinarlos en horno templado hasta que tomen color
    8. +
    + +

    NOTA: Cuando se enfrían se endurecen, así que al sacarlos del horno deben estar un poquito blandos

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/panqueques.html b/wiki/articles/panqueques.html new file mode 100644 index 0000000000..b3d67651e3 --- /dev/null +++ b/wiki/articles/panqueques.html @@ -0,0 +1,339 @@ + + + + + + + + + + + Panqueques + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Panqueques +

    +
    + + + +
    +

    Cantidad: 14 panqueques

    + +

    Ingredientes:

    + +
      +
    • 1 taza de harina (120gr)
    • +
    • 1 cucharadita de polvo de hornear
    • +
    • 1/4 de cucharadita de sal
    • +
    • 2 huevos
    • +
    • 1 taza de leche
    • +
    • 30 grs de manteca derretida
    • +
    • Esencia de vainilla
    • +
    + +

    Pasos:

    + +
      +
    1. Tamizar juntos la harina, el polvo de hornear y la sal.
    2. +
    3. Aparta batir los huevos y se les agrega la leche y la manteca derretida
    4. +
    5. Se vierte esta mezcla sobre los ingredientes secos y se bate hasta que el batido quede liso
    6. +
    7. Se le puede agregar un poco de esencia de vainilla
    8. +
    9. Se calienta una sarten con un poquito de manteca y ponen 1 cucharón del batido para que cubra toda la sarten
    10. +
    11. Se cuece a fuego moderado hasta que tome color y luego se lo da vuelta para cocer el otro lado
    12. +
    13. Si es para comer dulces, se los puede espolvorear con azúcar apenas se los saca de la sarten
    14. +
    15. Repetir hasta que se acabe el batido.
    16. +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-de-objetos---method-lookup.html b/wiki/articles/paradigma-de-objetos---method-lookup.html new file mode 100644 index 0000000000..7d94adcc3a --- /dev/null +++ b/wiki/articles/paradigma-de-objetos---method-lookup.html @@ -0,0 +1,427 @@ + + + + + + + + + + + Paradigma de objetos method lookup + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma de objetos method lookup +

    +
    + + + +
    +

    También conocido como Dynamic dispatch

    + +

    Es el mecanismo por el cual se relaciona el envío de un mensaje con la ejecución de un método determinado.

    + +

    Con objetos individuales

    + +

    Cuando definimos un objeto y le declaramos su propio comportamiento, este mecanismo es trivial. Si existe un método que se llame igual que el mensaje definido y con la misma cantidad de parámetros, se ejecutará ese método, de lo contrario tirará un error porque no entiende el mensaje (a menos que se trate de un mensaje básico como la igualdad o identidad que cualquier objeto entiende).

    + +

    Con clases y herencia simple

    + +

    ¿Qué pasa cuando a un objeto i instancia de la clase C se le envía un mensaje de nombre m?

    + +

    Tenemos (a efectos de entender el mecanismo porque esto lo hace internamente el ambiente) que mantener una referencia a la clase donde estamos buscando en un momento determinado.

    + +

    Al principio la clase actual es C y el objeto receptor del mensaje (self) es i.

    + +

    El algoritmo es el siguiente:

    + +

    1. se busca en la clase actual un método con el nombre m

    + +

    1a. si se encuentra se ejecuta el método encontrado; se ejecuta el método en el objeto i y se terminó el method lookup

    + +

    1b. si no se encuentra y la clase actual no es Object la clase actual pasa a ser la superclase de la clase actual y se vuelve a 1.

    + +

    1c. si no se encuentra y la clase actual es Object entonces el objeto i no entiende el mensaje m

    + +

    El comportamiento por defecto cuando un objeto no entiende un mensaje es lanzar un error.

    + +

    Ejemplo 1

    + +

    Si le enviamos el mensaje asUppercase al objeto 'hola' (o sea, al string 'hola') ¿qué debería pasar?

    + +

    Asumamos (porque no es así) que 'hola' es instancia de String, que String es subclase de Collection y que Collection es subclase de Object.

    + +

    Siguiendo el algoritmo de arriba a través de los pasos indicados con -

    + +

    i es 'hola'

    + +

    clase actual es String

    + +

    m es #asUppercase

    + +

    - se busca en String un método con el nombre #asUppercase

    + +

    - se encuentra el método #asUppercase en la clase String

    + +

    - se ejecuta el método #asUppercase de la clase String sobre i el objeto receptor del mensaje (o sea hola)

    + +

    Conclusión: 'hola' entiende el mensaje #asUppercase

    + +

    Ejemplo (heredando un método)

    + +

    Basándonos en el ejemplo 1, si le enviamos el mensaje == al objeto 'hola' (o sea, al string 'hola') ¿qué debería pasar?

    + +

    i es 'hola'

    + +

    clase actual es String

    + +

    m es #==

    + +

    - se busca en String un método con el nombre #==

    + +

    - no se encuentra el método #== en String y la clase actual no es Object entonces la clase actual pasa a ser Collection (la superclase de la clase actual) y se vuelve a 1.

    + +

    - se busca en Collection un método con el nombre #==

    + +

    - no se encuentra el método #== en Collection y la clase actual no es Object entonces la clase actual pasa a ser Object (la superclase de la clase actual) y se vuelve a 1.

    + +

    - se busca en Object un método con el nombre #==

    + +

    - se encuentra el método #== en la clase Object

    + +

    - se ejecuta el método #== de la clase Object sobre i, el objeto receptor del mensaje (o sea hola)

    + +

    Conclusión: 'hola' entiende el mensaje #==

    + +

    Ejemplo (no entiende el mensaje)

    + +

    Basándonos en el ejemplo 1, si le enviamos el mensaje factorial al objeto 'hola' (o sea, al string 'hola') ¿qué debería pasar?

    + +

    i es 'hola'

    + +

    clase actual es String

    + +

    m es #factorial

    + +

    - se busca en String un método con el nombre #factorial

    + +

    - no se encuentra el método #factorial en String y la clase actual no es Object entonces la clase actual pasa a ser Collection (la superclase de la clase actual) y se vuelve a 1.

    + +

    - se busca en Collection un método con el nombre #factorial

    + +

    - no se encuentra el método #factorial en Collection y la clase actual no es Object entonces la clase actual pasa a ser Object (la superclase de la clase actual) y se vuelve a 1.

    + +

    - se busca en Object un método con el nombre #factorial

    + +

    - no se encuentra y la clase actual es Object entonces el objeto i no entiende el mensaje m

    + +

    O dicho de otra forma, 'hola' no entiende el mensaje #factorial

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-de-objetos.html b/wiki/articles/paradigma-de-objetos.html new file mode 100644 index 0000000000..377f8c6521 --- /dev/null +++ b/wiki/articles/paradigma-de-objetos.html @@ -0,0 +1,476 @@ + + + + + + + + + + + Paradigma de objetos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma de objetos +

    +
    + + + +
    +

    Un objeto es un ente computacional que exhibe comportamiento (podemos comunicarnos con él mediante mensajes) y puede (o no) tener un estado interno (referencias a otros objetos).

    + +

    Un programa basado en este paradigma es un conjunto de objetos que interactúan entre sí en un ambiente mandándose mensajes para lograr un objetivo determinado.

    + +

    Intuición

    + +

    Intuitivamente, nuestra realidad parece estar conformada por muchos objetos: automóviles, mesas, frascos de mermelada, papeles, computadoras, cables. Esos objetos están allí, se pueden diferenciar entre ellos: una mesa y una silla son diferentes. Más importante aún, si tengo dos sillas, aunque hayan sido fabricadas en el mismo lugar, tengan la misma cantidad de patas y mismo tapizado, las puedo distinguir. Es decir, aunque dos objetos se vean muy parecidos, siguen siendo… ¡dos objetos diferentes! Los objetos se pueden diferenciar, porque tienen identidad propia.

    + +

    ¿Y por qué nos interesan los objetos? Cuando programamos, queremos resolver problemas, entonces no nos van a interesar tanto los objetos por sí mismos, sino que estos pueden resolver problemas. ¿Cómo es esto de resolver problemas? Simple: las hojas de papel nos sirven para escribir en ellas, los cables para conducir energía, los automóviles, para transportarnos. Es decir, no nos va a interesar la mesa porque tenga cuatro patas y una tabla de madera, sino porque esas cuatro patas y tabla nos permitirán resolver el problema de apoyar nuestro almuerzo. De los objetos, entonces, nos va a interesar que son capaces de hacer cosas: tienen comportamiento.

    + +

    Hay algo más que es interesante en los objetos: a veces estos cambian con el tiempo. Por ejemplo, las mesas se deterioran después de servir de sostén por mucho tiempo, el frasco de mermelada se vacía después de sacarle mermelada varias veces, el automóvil pierde nafta cuando se mueve, y gana nafta cuando se lo recarga. Los objetos pueden tener un estado, y el mismo puede cambiar.

    + +

    Entonces parece que la pregunta de qué es un objeto se responde fácil… es una cosa, pero no cualquier cosa: tiene identidad, estado y comportamiento.

    + +

    Ahora nos queda realizar un último salto: en realidad hay más cosas, más objetos en nuestro mundo, que sólo automoviles, hojas o mesas. Hay por ejemplo, países, culturas,trabajos, problemas, ideas, sentimientos. Y una idea se puede diferenciar de otra (identidad), un trabajo puede resolverlos el problema de tener dinero a fin de mes (comportamiento), y un país puede cambiar (estado). Los objetos, entonces, pueden ser también cosas que no podemos tocar: cosas intangibles.

    + +

    El paradigma de objetos nos propone justamente resolver nuestros problemas usando, adivinen…..¡objetos!. Y para eso, tendremos que zambullirnos en un mundo de objetos.

    + +

    Teoría

    + + + +

    Colecciones

    + + + +

    Cosas que pueden servir para pensar en cómo modelar un enunciado

    + + + +

    Un poco más sobre Smalltalk

    + + + +

    Miscelánea

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-de-programacion.html b/wiki/articles/paradigma-de-programacion.html new file mode 100644 index 0000000000..bc8ad9b8dd --- /dev/null +++ b/wiki/articles/paradigma-de-programacion.html @@ -0,0 +1,369 @@ + + + + + + + + + + + Paradigma de programacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma de programacion +

    +
    + + + +
    +

    Un paradigma de programación es un marco conceptual, un conjunto de ideas que describe una forma de entender la construcción de programa, como tal define:

    + +
      +
    • Las herramientas conceptuales que se pueden utilizar para construir un programa (objetos, relaciones, funciones, instrucciones).
    • +
    • Las formas válidas de combinarlas.
    • +
    + +

    Los distintos lenguajes de programación proveen implentaciones para las herramientas conceptuales descriptas por los paradigmas. Existen lenguajes que se concentran en las ideas de un único paradigma así como hay otros que permiten la combinación de ideas provenientes de distintos paradigmas.

    + +

    Dado que un paradigma es un conjunto de ideas, su influencia se ve principalmente en el momento de modelar una solución a un problema dado. No es suficiente saber en qué lenguaje está construido un programa para saber qué marco conceptual se utilizó en el momento de construirlo. El paradigma tiene más relación con el proceso mental que se realiza para construir un programa que con el programa resultante.

    + +

    ¿Qué es un programa?

    + +

    Para definir programa es necesario analizarlo desde dos diferentes perspectivas. Uno de esos puntos de vista es análogo al del usuario del programa, interesado en la tarea que realizar el programa. Desde esa perspectiva un programa es aquello que permite que una computadora realice una tarea determinada.

    + +

    El otro punto de vista es el de aquel que tenga que construir o modificar ese programa (programador), a quien interesará también la forma en que está construido. Desde esta perspectiva no hay una única definición al concepto de programa ya que cada paradigma ofrece una respuesta distinta a esta pregunta.

    + +

    Paradigma Estructurado
    +Secuencia ordenada de instrucciones que manipulan un espacio de memoria.

    + + + +

    Paradigma de Objetos
    +Conjunto de objetos que se conocen entre sí a través de referencias y se envían mensajes en un ambiente.

    + + + +

    Paradigma Lógico
    +Conjunto de predicados definidos a través de cláusulas (hechos y reglas) que describen propiedades y relaciones de un conjunto de individuos, sobre los cuales podemos realizar consultas.

    + + + +

    Paradigma Funcional
    +Conjunto de funciones (relaciones que cumplen las propiedades de unicidad y existencia), que pueden ser evaluadas para obtener un resultado.

    + +

    Otras Ideas

    + +
      +
    • Modelar la realidad, o mejor dicho que el programa se acerque a la realidad (vs. tener un diseño y luego un programa lejano a eso)
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-funcional.html b/wiki/articles/paradigma-funcional.html new file mode 100644 index 0000000000..bb84413035 --- /dev/null +++ b/wiki/articles/paradigma-funcional.html @@ -0,0 +1,450 @@ + + + + + + + + + + + Paradigma funcional + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma funcional +

    +
    + + + +
    +

    Introducción

    + +

    Este paradigma se basa en un conjunto de funciones (relaciones que cumplen las propiedades de unicidad y existencia), que pueden ser evaluadas para obtener un resultado. El paradigma funcional está basado en conceptos que vienen de la matemática, entonces algunas cosas (p.ej. notaciones en el lenguaje) están sacadas de lo que aprendimos en Análisis I / Álgebra / Discreta.

    + +

    Conceptos generales

    + + + +

    Tipos

    + + + +

    Extras simpáticos

    + + + +

    Errores comunes

    + + + +

    Para aprender más sobre el lenguaje Haskell

    + + + +

    Problemas complejos y cosas locas

    + +

    Acá hay algunas cosas interesantes que escapan al nivel de funcional que se espera que aprendan para Paradigmas, si te interesa profundizar en el tema es muy interesante!

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---casos-de-no-inversibilidad.html b/wiki/articles/paradigma-logico---casos-de-no-inversibilidad.html new file mode 100644 index 0000000000..f9cc551d85 --- /dev/null +++ b/wiki/articles/paradigma-logico---casos-de-no-inversibilidad.html @@ -0,0 +1,796 @@ + + + + + + + + + + + Paradigma logico casos de no inversibilidad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico casos de no inversibilidad +

    +
    + + + +
    +

    Introducción

    + +

    Los casos de no inversibilidad, y algunos de no funcionamiento o respuestas incorrectas, están relacionados con variables que no están ligadas en cierto punto (recordando que el análisis debe hacerse “de izquierda a derecha”) y deben estarlo, o (menos probable) al revés, variables que deben llegar a cierto punto sin ligar y están ligadas.

    + +

    Veamos varios casos, que incluyen todos los casos de no-inversibilidad que vemos en la materia.

    + +

    Hechos con variables

    + +

    Por lo general aquellos predicados definidos en base a hechos no suelen ser problemáticos, porque lo normal es que incluyan información sobre los individuos a los cuales se refieren. Sin embargo, el siguiente es un hecho válido que no es inversible para su segunda aridad:

    + +
    +
    +
    +      leGusta(pepe, _).
    +
    +    
    +
    +
    + +

    Eso dice que a pepe le gusta cualquier cosa, sin acotar de ninguna forma qué podría ser aquello que le gusta. Para hacer el predicado inversible, deberíamos acotar qué puede ser aquello que le gusta convirtiéndolo en una regla, por ejemplo:

    + +
    +
    +
    +      leGusta(pepe, Comida):- comida(Comida).
    +
    +    
    +
    +
    + +

    Negación

    + +

    Negación: las variables que aparecen en la parte de la cláusula deben llegar ligadas, a menos que sean variables afectadas por un “para ningún”, en este caso deben llegar libres. P.ej. esta definición del predicado esPlantaComestible

    + +
    +
    +
    +       esPlantaComestible(Planta):- not(esVenenosa(Planta)).
    +
    +    
    +
    +
    + +

    no es inversible, porque Planta debe estar ligada antes de llegar al not. ¿Por qué? Ver Paradigma Lógico - negación +Para hacer al predicado inversible, generamos el dominio de la variable Planta

    + +
    +
    +
    +      esPlantaComestible(Planta):- esPlanta(Planta), not(esVenenosa(Planta)).
    +
    +    
    +
    +
    + +

    Aritmética

    + +

    **Aritmética: ** todas las variables a la derecha del is deben llegar ligadas al is. P.ej. el predicado precioPorCantidad definido así

    + +
    +
    +
    +       precioPorCantidad(Planta,Cantidad,PrecioTotal):- 
    +       precioPlanta(Planta,Precio), PrecioTotal is Cantidad * Precio.
    +
    +    
    +
    +
    + +

    no es inversible para el 2do argumento, porque si no se indica un número para Cantidad en la consulta, al llegar a la cuenta hay una variable no ligada a la derecha del is. +En este caso no hay forma trivial de arreglarlo para que el predicado sea totalmente inversible.

    + +

    En este caso

    + +
    +
    +
    +       importeCompra(Persona, ImporteTotal):- 
    +       ImporteTotal is Precio*1.21, compra(Persona, Planta), 
    +       precioPlanta(Planta,Precio).
    +
    +    
    +
    +
    + +

    ninguna consulta que involucre a esta cláusula va a andar porque no hay forma de que la variable Precio esté ligada al momento de hacer la cuenta. Arreglar este caso es fácil: ponemos el is al lado del punto

    + +
    +
    +
    +       importeCompra(Persona, ImporteTotal):- 
    +       compra(Persona, Planta), 
    +       precioPlanta(Planta,Precio), 
    +       ImporteTotal is Precio*1.21.
    +
    +    
    +
    +
    + +

    Comparación

    + +

    Si se compara por mayor, menor, mayor o igual, menor o igual, distinto, lo que comparemos debe estar ligado. P.ej. esta definición

    + +
    +
    +
    +       plantaHeavy(Planta):-Nivel > 5, nivelVeneno(Planta,Nivel).
    +
    +    
    +
    +
    + +

    es incorrecta, porque Nivel no está ligado al momento de comparar. Esta forma

    + +
    +
    +
    +       plantaHeavy(Planta):-nivelVeneno(Planta,Nivel),Nivel > 5.
    +
    +    
    +
    +
    + +

    sí es correcta.

    + +

    Findall

    + +

    Miremos esta definición de plantasDerivadasDe

    + +
    +
    +
    +       plantasDerivadasDe(Planta, ListaPlantasFamiliares):- 
    +    findall(P2, derivadaDe(Planta,P2), ListaPlantasFamiliares).
    +
    +    
    +
    +
    + +

    y supongamos esta consulta

    + +
    +
    +
    +       ?- plantasDerivadasDe(Pl, Plantas).
    +
    +    
    +
    +
    + +

    Miremos fijos el findall, recordando que unifica el 3er argumento con la lista de la parte indicada en el 1er argumento de todas las respuestas a la consulta del 2do argumento. +En este caso: va a ligar ListaPlantasFamiliares con la lista de los P2 para cada respuesta a la consulta derivaDe(Planta,P2). +Como en la consulta no se liga Planta, entonces las respuestas a derivaDe(Planta,P2) van a ser todos los pares de plantas (planta,derivada), y por lo tanto los P2 van a ser todas las plantas derivadas de alguna planta. +P.ej. si tenemos

    + +
    +
    +
    +       derivaDe(p1,p3).
    + derivaDe(p2,p4).
    + derivaDe(p2,p5).
    +
    +    
    +
    +
    + +

    ListaPlantasFamiliares va a ser [p2,p4,p5]. Esto nos muestra que con esta definición el predicado no es inversible para el primer argumento, porque las listas de “derivadas de la misma planta” son [p3] por un lado, y [p4,p5] por otro; [p2,p4,p5] no puede ser un 2do argumento correcto para este predicado.

    + +

    Para que que el predicado sea totalmente inversible debemos asegurar que la variable Planta entra ligada al findall.

    + +
    +
    +
    +       plantasDerivadasDe(Planta, ListaPlantasFamiliares):- 
    +    esPlanta(Planta), 
    +    findall(P2, derivaDe(Planta,P2), ListaPlantasFamiliares).
    +
    +    
    +
    +
    + +

    Miremos ahora qué pasa si definimos el predicado así

    + +
    +
    +
    +       plantasDerivadasDe(Planta, ListaPlantasFamiliares):- 
    +    esPlanta(Planta), derivaDe(Planta,P2), 
    +    findall(P2, derivaDe(Planta,P2), ListaPlantasFamiliares).
    +
    +    
    +
    +
    + +

    En este caso, al llegar al findall tanto Planta como P2 ya están ligadas, entonces la consulta derivaDe(Planta,P2) puede tener a lo sumo una respuesta (positiva, la respuesta “no” no se cuenta), entonces ListaPlantasFamiliares va a tener a lo sumo un elemento. Vamos a obtener respuestas incorrectas, p.ej.

    + +
    +
    +
    +       ?- plantasDerivadasDe(p2, Lista).
    + Lista = [p4]
    +
    +    
    +
    +
    + +

    porque la variable P2, que debe llegar sin ligar al findall, llega ligada.

    + +

    Un ejemplo futbolero

    + +
    +
    +
    +          ganoContra(argentina, suiza).
    +    ganoContra(argentina, belgica).
    +    ganoContra(argentina, holanda).
    +
    +    ganoContra(belgica, eeuu).
    +
    +    ganoContra(holanda, mexico).
    +
    +    superEquipo( Equipo ) :- findall(P, ganoContra(Equipo, P), Partidos), length(Partidos, CantGanados), CantGanados > 2.
    +
    +    
    +
    +
    + +

    Ahora fijate tirando en prolog la siguiente consulta:

    + +
    +
    +
    +          superEquipo( X ).
    +
    +    
    +
    +
    + +

    Forall

    + +

    Esta definición del predicado esEspecieComestible

    + +
    +
    +
    +       esEspecieComestible(Especie):- 
    +     forall(especieDe(Planta,Especie), esPlantaComestible(Planta)).
    +
    +    
    +
    +
    + +

    no es inversible, porque Especie debe llegar ligado al forall. Si no llega ligada, para que el forall se verifique deben ser comestibles todas las plantas que sean de alguna especie. Esto está explicado en detalle en el artículo sobre forall.

    + +

    Para que sea inversible debemos generar el dominio para la variable Especie

    + +
    +
    +
    +       esEspecieComestible(Especie):- 
    +     esEspecie(Especie),
    +     forall(especieDe(Planta,Especie), esPlantaComestible(Planta)).
    +
    +    
    +
    +
    + +

    Functores y polimorfismo

    + +

    Como caso particular de los hechos con variables, algo muy común es tener definiciones como:

    + +
    +
    +
    +      marca(arroz(Marca),Marca).
    +marca(lacteo(Marca,_),Marca).
    +
    +    
    +
    +
    + +

    El predicado marca/2 nos va a resultar muy útil para cuando no nos interese qué tipo concreto de producto se está usando, sólo que tenga una marca y nos la sepa decir. Lo importante es ser conscientes de que este predicado no es inversible, con lo cual sería incorrecto tratar de usarlo como generador de marcas por ejemplo. Si nos interesa que sea inversible tenemos que usar otro predicado que nos genere los productos, por ejemplo:

    + +
    +
    +
    +      marca(arroz(Marca),Marca):- precioUnitario(arroz(Marca),_).
    +marca(lacteo(Marca,TipoLacteo),Marca):- precioUnitario(lacteo(Marca,TipoLacteo),_).
    +
    +    
    +
    +
    + +

    En resumen

    + +

    Resumimos los casos de inversibilidad con un ejemplo de cada uno

    + +

    Hechos con variables

    + +
    +
    +
    +       leGusta(pepe, _).
    + % Lo que le gusta debería acotarse de alguna forma si se pretenden hacer consultas existenciales sobre la segunda aridad
    +
    +    
    +
    +
    + +

    Negación

    + +
    +
    +
    +       esPlantaComestible(Planta):- not(esVenenosa(Planta)).
    + % Planta debe llegar ligada al not
    +
    +    
    +
    +
    +

    Aritmética

    + +
    +
    +
    +       precioPorCantidad(Planta,Cantidad,PrecioTotal):- 
    +     precioPlanta(Planta,Precio), PrecioTotal is Cantidad * Precio.
    + % Cantidad debe llegar ligada al is
    +
    +    
    +
    +
    + +

    Comparación

    + +
    +
    +
    +       plantaHeavy(Planta):- Nivel > 5, nivelVeneno(Planta,Nivel).
    + % Nivel debe llegar ligada a la comparación
    +
    +    
    +
    +
    + +

    findall

    + +
    +
    +
    +       plantasDerivadasDe(Planta, ListaPlantasFamiliares):- 
    +     findall(P2, derivadaDe(Planta,P2), ListaPlantasFamiliares).`` % Planta debe llegar ligada al findall`
    +
    +    
    +
    +
    + +

    forall

    + +
    +
    +
    +       esEspecieComestible(Especie):- 
    +     forall(especieDe(Planta,Especie), esPlantaComestible(Planta)).` % Especie debe llegar ligada al forall`
    +
    +    
    +
    +
    + +

    Functores y Polimorfismo

    + +
    +
    +
    +       marca(arroz(Marca),Marca).
    + marca(lacteo(Marca,_),Marca).
    + % Si pretendemos usar marca/2 para hacer consultas existenciales, no puede tener _ ni variables que no se generen internamente en el encabezado.
    +
    +    
    +
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---como-pienso-la-resolucion-de-un-punto.html b/wiki/articles/paradigma-logico---como-pienso-la-resolucion-de-un-punto.html new file mode 100644 index 0000000000..7b7b79dfab --- /dev/null +++ b/wiki/articles/paradigma-logico---como-pienso-la-resolucion-de-un-punto.html @@ -0,0 +1,400 @@ + + + + + + + + + + + Paradigma logico como pienso la resolucion de un punto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico como pienso la resolucion de un punto +

    +
    + + + +
    +

    Ejemplo

    + +
    tour(lokotour,[tramo(madrid,roma), tramo(roma,bonn), tramo(bruselas,burdeos)]).
    +tour(eurobleh,[tramo(madrid,perpignan), tramo(perpignan,paris), tramo(paris,praga)]).
    +
    +pais(bsas,argentina).
    +pais(mendoza,argentina).
    +pais(lima,peru).
    +pais(quito,ecuador).
    +pais(caracas,venezuela).
    +pais(toronto,canada).
    +pais(montreal,canada).
    +
    +pais(madrid,espania).
    +pais(toledo,espania).
    +pais(roma,italia).
    +pais(bonn,alemania).
    +pais(bruselas,belgica).
    +pais(burdeos,francia).
    +pais(perpignan,francia).
    +pais(paris,francia).
    +pais(praga,repcheca).
    +
    +pais(sydney, australia).
    +
    +ciudadGrosa(bsas).
    +ciudadGrosa(lima).
    +ciudadGrosa(quito).
    +ciudadGrosa(caracas).
    +ciudadGrosa(montreal).
    +ciudadGrosa(toledo).
    +
    + +

    Qué no hago

    + +

    Pensar en recorrer, no hay que recorrer nada.

    + +

    Qué hago

    + +

    Si tengo que crear un predicado nuevo, pienso en la aridad, y qué representa cada argumento.

    + +

    P.ej. el predicado pasaPorPais relaciona un tour con un país, entonces es de aridad 2.

    + +

    Pienso en qué condiciones se tienen que dar, y busco la forma (con las herramientas que tengo) de expresarlo en Prolog.

    + +

    Cuando termino, pongo el punto al final de la última cláusula … y ya está, no-hay-nada-más-que-hacer.

    + +

    P.ej. ¿cuándo es cierto que un tour T pasa por un país P? Cuando la lista de ciudades de T incluye alguna del país P.

    + +

    Hay muchas veces en que necesito un individuo que no es un argumento del predicado. En ese caso, pienso qué condiciones la relacionan con los individuos que ya tengo (argumentos + los que traje en condiciones anteriores en la misma cláusula). Típicamente, voy a designar estos nuevos individuos con variables, o con cosas más complejas si me conviene aplicar pattern matching.

    + +

    Veamos algunos ejemplos:

    + +

    Tenemos que hacer el predicado paisInteresante/1, un país es interesante si tiene al menos dos ciudades grosas.

    + +

    En este caso necesito dos ciudades del país, las voy a llamar C1 y C2.

    + +

    ¿Qué condiciones tienen que cumplir C1 y C2?

    + +
      +
    • Ser del país, predicado pais/2 que relaciona ciudad con país (¡¡en ese orden!!). El país lo tengo, es el argumento de paisInteresante
    • +
    • Ser grosas, predicado ciudadGrosa/1
    • +
    + +

    Queda

    + +

       paisInteresante(P):- ciudad(C1,P), ciudad(C2,P), ciudadGrosa(C1), ciudadGrosa(C2).

    + +

    Resolvamos pasaPorPais/2 … acá necesitamos

    + +
      +
    • la lista de ciudades, para eso tenemos el predicado tour/2, la voy a llamar LCiud.
    • +
    • la ciudad, a la que voy a llamar C. ¿Qué le tiene que pasar a C? Estar en LCiud (member/2) y ser del país (pais/2)
    • +
    + +

    Queda

    + +

       pasaPorPais(Tour,Pais):- tour(Tour,LCiud), member(C,LCiud), pais(C,Pais).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---conjuncion-y-disyuncion.html b/wiki/articles/paradigma-logico---conjuncion-y-disyuncion.html new file mode 100644 index 0000000000..e6ea878870 --- /dev/null +++ b/wiki/articles/paradigma-logico---conjuncion-y-disyuncion.html @@ -0,0 +1,410 @@ + + + + + + + + + + + Paradigma logico conjuncion y disyuncion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico conjuncion y disyuncion +

    +
    + + + +
    +

    Las operaciones lógicas por excelencia son la conjunción (“Y”, sólo es cierta si ambas condiciones son ciertas) y la disyunción (“O”, es cierta si alguna de las condiciones es cierta).

    + +

    Tenemos la siguiente base de conocimiento:

    + +
     madre(nora,luis).
    + madre(nora,ana).
    + madre(lidia,jose).
    + madre(dora,juan).
    + padre(juan,luis).
    + padre(juan,ana).
    + padre(juan,jose).
    + padre(antonio,juan).
    +
    + +

    Supongamos que tenemos que desarrollar en Prolog un predicado hermano/2 que relaciona a dos personas si tienen el mismo padre y la misma madre, y otro llamado hermanastro/2 que relaciona a dos personas si tienen al padre o a la madre en común (para el ejemplo no se considerará que el O sea excluyente, por ende dos personas hermanas también serán hermanastras).

    + +

    La relación de hermano, dada nuestra base de conocimientos, debería cumplirse para luis y ana, mientras que Jose es sólo hermanastro de Luis y Ana. Juan en cambio es hijo único, con lo cual no debería satisfacer ninguna de las relaciones.

    + +

    Codifiquemos los predicados hermano/2 y hermanastro/2:

    + +
     hermano(Persona,Hermano):-
    +   mismoPadre(Persona,Hermano),
    +   mismaMadre(Persona,Hermano).
    +
    + hermanastro(Persona,Hermanastro):- mismaMadre(Persona,Hermanastro).
    + hermanastro(Persona,Hermanastro):- mismoPadre(Persona,Hermanastro).
    +
    + mismoPadre(Persona1,Persona2):- 
    +   padre(Padre,Persona1),
    +   padre(Padre,Persona2).
    +
    + mismaMadre(Persona1,Persona2):- 
    +   madre(Madre,Persona1),
    +   madre(Madre,Persona2).
    +
    + +

    La conjunción en Prolog se logra con la coma, mientras que la disyunción la conseguimos mediante la definición de varias cláusulas para el mismo predicado. Podemos ver a partir del predicado hermanastro que la búsqueda de soluciones que realiza el motor de Prolog es exhaustiva, ya que si bien jose y luis no cumplen la condición de tener la misma madre, el resultado a la consulta hermanastro(jose,luis) es verdadero, dado que continúa la evaluación con las otras alternativas para poder satisfacer la relación.

    + +

    Error común: Hacer el “O” antes de tiempo

    + +

    Vamos a suponer que tenemos la siguiente lógica “una pc es gamer si tiene un disco ssd, un procesador multinúcleo, y una placa de video shifors 6 o una reidion 8” +El siguiente código está mal, porque repite lógica:

    + +
    esGamer(PC):-
    +  tieneDiscoSSD(PC),
    +  tieneMultiNucleo(PC),
    +  placa(PC,shifors6).
    +  
    +esGamer(PC):-
    +  tieneDiscoSSD(PC),
    +  tieneMultiNucleo(PC),
    +  placa(PC,reidion8).
    +  
    + % ¡REPITE LÓGICA!
    +
    + +

    La definición de una pc gamer debe ser única, es decir, tiene que tener una sola cláusula. ¡Hay una sola forma de que una pc sea gamer, no dos! +¿Cómo? ¡Nos falta una abstracción! La abstracción tienePlacaBuena. Implícitamente esa idea está, pero nos falta en nuestro código. Veamos cómo agregando esa abstracción evitamos la repetición de lógica:

    + +
    +

    “una pc es gamer si tiene un disco ssd, un procesador multinúcleo, y una buena placa de video

    +
    + +
    esGamer(PC):-
    +  tieneDiscoSSD(PC),
    +  tieneMultiNucleo(PC),
    +  tienePlacaBuena(PC).
    +  
    +tienePlacaBuena(PC):-
    +  placa(PC,shifors6).
    +  
    +tienePlacaBuena(PC):-
    +  placa(PC,reidion8).
    +
    +% No repite lógica: la definición de "esGamer" es única, delega en otro predicado "tienePlacaBuena" los detalles.
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---detalles-del-swi-prolog.html b/wiki/articles/paradigma-logico---detalles-del-swi-prolog.html new file mode 100644 index 0000000000..fb547db2a8 --- /dev/null +++ b/wiki/articles/paradigma-logico---detalles-del-swi-prolog.html @@ -0,0 +1,319 @@ + + + + + + + + + + + Paradigma logico detalles del swi prolog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico detalles del swi prolog +

    +
    + + + +
    +

    Ojo con los espacios

    + +

    Hay un lugar en donde no puede haber ningún espacio, que es entre el nombre del predicado o functor y el paréntesis que abre. O sea, ninguna de las siguientes cláusulas compila

    + +

       bueno(X):- not (malo(X)).   +   esTierno(P):- forall (leGusta(P,A), dulce(A)). +   leGusta (copion,C):- leGusta(pepe,C). +   leGusta(copion,C):- leGusta (pepe,C). +   tiene(pepe,libro (octaedro,cortazar)).

    + +

    hay que poner

    + +

       bueno(X):- not(malo(X)).   +   esTierno(P):- forall(leGusta(P,A), dulce(A)). +   leGusta(copion,C):- leGusta(pepe,C). +   tiene(pepe,libro(octaedro,cortazar)).

    + +

    los espacios en otros lados no molestan, p.ej.

    + +

       leGusta( copion , C ) :- leGusta( pepe , C ) . +   tiene( pepe , libro( octaedro , cortazar ) ) .

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---el-forall.html b/wiki/articles/paradigma-logico---el-forall.html new file mode 100644 index 0000000000..dd32d9e5e3 --- /dev/null +++ b/wiki/articles/paradigma-logico---el-forall.html @@ -0,0 +1,664 @@ + + + + + + + + + + + Paradigma logico el forall + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico el forall +

    +
    + + + +
    +

    Antes que nada

    + +

    El forall es un predicado, o sea, no conviene pensar qué “hace”, sino qué relaciona, y/o cuándo se verifica. +El predicado forall conviene pensarlo por lo segundo, o sea cuándo se verifica.

    + +

    Definición

    + +

    El forall recibe dos parámetros, los dos deben ser consultas. Las consultas se hacen sobre predicados, o sea que forall es un predicado de orden superior, porque puede manejar predicados dentro de sus parámetros.

    + +

    Hagámosnos la pregunta … ¿cuándo se verifica? +Cuando a todos los que les pasa lo primero, les pasa lo segundo. +Dicho un poco más “en técnico”, cuando todas las respuestas de la primer consulta son respuestas de la segunda.

    + +

    Entonces, en las situaciones donde decimos “a todos los que …blah… les pasa …bleh…” es probable que el forall nos venga bien.

    + +

    Un ejemplo

    + +

    partimos de estos hechos

    + +
    +
    +
    +          dulce(chocolate).
    +    dulce(caramelo).
    +    dulce(durazno).
    +    amargo(radicheta).
    +    amargo(cebada).
    +
    +    leGusta(roque,chocolate).
    +    leGusta(roque,radicheta).
    +    leGusta(pepe,cebada).
    +    % ... y muchos hechos más que describen los gustos de un grupo de personas
    +
    +    colorDePelo(roque,colorado).
    +    colorDePelo(pepe,castanio).
    +    % ... etc. con los colores de pelo
    +
    +    vive(roque,buenosAires).
    +    vive(pepe,mendoza).
    +    vive(lucas,salliquelo).
    +    % ... y donde vive cada persona de la que queremos hablar
    +
    +    ciudadGrande(buenosAires).
    +    ciudadGrande(mendoza).
    +    % ... y así todas las ciudades grandes
    +
    +    
    +
    +
    + +

    y queremos definir esTierno/1, donde decimos que una persona es tierna si todas las cosas que le gustan son dulces.

    + +

    Estamos en un caso candidato a forall: “a todas las cosas que le gustan les tiene que pasar ser dulces”. En Prolog:

    + +
    +
    +
    +         esTierno(Persona):- forall(leGusta(Persona, Alimento), dulce(Alimento)).
    +
    +    
    +
    +
    + +

    … una Persona es tierna si … todas las cosas que le gustan son dulces, exactamente lo que dijimos en castellano.

    + +

    Ahora quiero definir el predicado alimentoCurioso/1, un alimento es curioso si solamente le gusta a gente de pelo colorado. +Para darme cuenta que el forall me puede servir, lo pienso en términos de “a todos los que … les tiene que pasar …”. A veeer

    + +
      +
    • a todas las personas que … les gusta el alimento
    • +
    • les tiene que pasar … ser coloradas
    • +
    + +

    Queda

    + +
    +
    +
    +         alimentoCurioso(Alimento):- forall(leGusta(Persona, Alimento), esColorado(Persona)).
    +
    +    
    +
    +
    + +

    Tener claro lo que se quiere decir

    + +

    ¿Está bien si defino esTierno así?

    + +
    +
    +
    +         esTierno(Persona):- forall(dulce(Alimento), leGusta(Persona, Alimento)).
    +
    +    
    +
    +
    + +

    Claramente no, porque estaría pidiendo que le gusten todos los alimentos dulces.

    + +

    Si programar va a consistir en definir condiciones, es relevante entender la diferencia entre

    + +
      +
    • todos los alimentos que le gustan son dulces, y
    • +
    • le gustan todos los alimentos dulces.
    • +
    + +

    El forall en acción

    + +

    Supongamos que hacemos esta consulta:

    + +
    +
    +
    +         ?- esTierno(roque).
    +
    +    
    +
    +
    + +

    La variable Persona de esTierno se liga con roque … entonces el forall se va a verificar (ver la definición técnica) cuando

    + +
      +
    • +

      todas las respuestas a la consulta + leGusta(roque,Alimento)

      +
    • +
    • +

      verifiquen la consulta + dulce(Alimento)

      +
    • +
    + +

    Para cada respuesta a la consulta leGusta(roque,Alimento), la variable Alimento se va a ligar, en el ejemplo hay dos respuestas, una con chocolate y otra con cebada. +La consulta correspondiente ya viene con esa variable ligada, o sea que las consultas que se tienen que verificar para que se verifique el forall son

    + +
    +
    +
    +         esDulce(chocolate).
    +   esDulce(cebada).
    +
    +    
    +
    +
    + +

    Volvamos a la definición: el forall se verifica si todas las respuestas a la primer consulta son respuestas de la segunda. Mirando el ejemplo de recién debería cerrar el esquema.

    + +

    ¿Qué pasa si no hay soluciones para el primer parámetro de forall?

    + +

    ¿Qué pasa si consultamos si lucas es tierno y en nuestra base de conocimientos no hay nada que le guste?

    + +
    +
    +
    +         ?- esTierno(lucas).
    +
    +    
    +
    +
    + +

    Esta consulta va a ser cierta, porque si no le gusta nada, es cierto que todas las cosas que le gustan son dulces. Si nos interesa que sólo diga verdadero para las personas que les gusta algo, debemos agregar otra condición fuera del forall que lo asegure.

    + +

    Forall e inversibilidad

    + +

    Veamos qué pasa con las variables y la inversibilidad. +¿Será inversible el predicado esTierno/1? Hagamos la consulta con una variable en el argumento

    + +
    +
    +
    +         ?- esTierno(X).
    +
    +    
    +
    +
    + +

    En este caso la variable Persona llega sin ligar al forall. Entonces la primer consulta es

    + +
    +
    +
    +         leGusta(Persona, Alimento).
    +
    +    
    +
    +
    + +

    Para cada una de las respuestas a esta consulta, se tiene que verificar

    + +
    +
    +
    +         esDulce(Alimento)
    +
    +    
    +
    +
    + +

    donde Alimento es lo que ligó la primer consulta.

    + +

    ¿Cuáles son las respuestas a la primer consulta? Todos los pares (persona,alimento) relacionados por leGusta. +Entonces, el forall sólo se va a verificar si cualquier cosa que le guste a alguien, no importa a quién, es dulce.

    + +

    Claro, no es lo que queremos. Para lograr lo que queremos, tenemos que lograr que la variable Persona llegue ligada al forall mediante generación:

    + +
    +
    +
    +         esTierno(Persona):- persona(Persona), forall(leGusta(Persona, Alimento),esDulce(Alimento)).
    +
    +    
    +
    +
    + +

    Una que no falla:

    + +

    fíjense que siempre decimos “a todos los blah que les pasa la consulta 1, les tiene que pasar la consulta 2”.

    + +

    Bueno, para ese “blah” va a haber una variable, que es Alimento en el caso de esTierno (si todos los alimentos que le gustan …) y P para alimentoCurioso (si todas las personas a quienes les gusta …). Esa variable tiene que llegar al forall sin ligar. El resto de las variables por lo general deben llegar ligadas.

    + +

    Varias condiciones

    + +

    Qué pasa si se tienen que cumplir varias condiciones: digamos que un alimento es peculiar si todas las personas a las que le gusta son colorados y porteños … nos queda

    + +
      +
    • a todas las personas que … les gusta el alimento
    • +
    • les tiene que pasar … ser coloradas y ser porteñas
    • +
    + +

    entonces la segunda consulta es un “y” entre dos condiciones.

    + +

    Si pongo

    + +
    +
    +
    +        esPeculiar(Alimento):- forall(leGusta(Persona, Alimento), colorDePelo(Persona, colorado), vive(Persona,buenosAires)).
    +
    +    
    +
    +
    + +

    está mal, porque el forall lleva dos parámetros, no tres. Necesito agrupar colorDePelo(…) y vive(…), para eso los encierro entre paréntesis, queda

    + +
    +
    +
    +        esPeculiar(Alimento):- forall(leGusta(Persona, Alimento), (colorDePelo(Persona, colorado), vive(Persona, buenosAires))).
    +
    +    
    +
    +
    + +

    Pregunto: ¿está bien

    + +
    +
    +
    +        esPeculiar(Alimento):- forall((leGusta(Persona, Alimento), colorDePelo(Persona, colorado)), vive(Persona, buenosAires)).
    +
    +    
    +
    +
    + +

    ? No, porque estaría pidiendo que todos los colorados a los que les gusta el alimento vivan en Buenos Aires.

    + +

    Para pensar

    + +

    Una que les queda para pensar: ahora tengo que decir que un alimento es marketinable si todas las personas a las que les gusta viven en ciudades grandes. No me interesa que el predicado sea inversible.

    + +

    Tiro tres opciones: elijan la correcta y piensen por qué eligieron esa.

    + +
    +
    +
    +         esMarketinable(Alimento):- forall(leGusta(Persona, Alimento), vive(Persona, Ciudad), ciudadGrande(Ciudad)).    % opción 1
    +   esMarketinable(Alimento):- forall((leGusta(Persona, Alimento), vive(Persona, Ciudad)), ciudadGrande(Ciudad)).  % opción 2
    +   esMarketinable(Alimento):- forall(leGusta(Persona, Alimento), (vive(Persona, Ciudad), ciudadGrande(Ciudad))).  % opción 3
    +
    +    
    +
    +
    + +

    Más sobre forall

    + +

    Léanse Paradigma Lógico - forall - no siempre con member

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---existe-vs-para-todo.html b/wiki/articles/paradigma-logico---existe-vs-para-todo.html new file mode 100644 index 0000000000..44fcb791e4 --- /dev/null +++ b/wiki/articles/paradigma-logico---existe-vs-para-todo.html @@ -0,0 +1,347 @@ + + + + + + + + + + + Paradigma logico existe vs para todo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico existe vs para todo +

    +
    + + + +
    +

    En la lógica de primer orden se trabaja con variables cuantificadas, los cuantificadores indican si algo se cumple para alguno (cuantificador existencial) o para todos (cuantificador universal) los valores de un conjunto de individuos.

    + +

    Lo más normal es trabajar con el cuantificador existencial, motivo por el cual en el lenguaje Prolog no hay un predicado que la denote, como sí sucede para el cuantificador universal.

    + +

    Si queremos definir un predicado estaComplicado/1 que se cumpla para las personas que tienen algún hijo problemático, podríamos hacer:

    +
    estaComplicado(Persona):-
    +   padre(Persona, Hijo),
    +   problematico(Hijo).
    +
    + +

    Si luego queremos definir estaHarto/1 de modo que se cumpla para las personas qué sólo tiene hijos problemáticos, deberíamos usar el predicado forall para cuantificar con Para Todo a los hijos de la persona en cuestión:

    +
    estaHarto(Persona):-
    +   padre(Persona, _),  %% Generamos a la persona porque no quiero que sea una variable a cuantificar
    +                       %% por el para todo, sino un individuo concreto. Además restringe el universo de respuestas
    +                       %% a personas que tengan al menos un hijo.
    +   forall(padre(Persona, Hijo), problematico(Hijo)).
    +
    + +

    Relación entre Existe y Para Todo

    + +

    Existe una relación entre el cuantificador universal y el existencial, la misma se establece mediante la negación.

    + +

    Podríamos haber hecho una solución para estaHarto/1 sin usar forall basándonos en esta equivalencia lógica. Alguien está harto si ninguno de sus hijos no es problemático.

    +
    estaHarto(Persona):-
    +   padre(Persona, _),
    +   not( (padre(Persona, Hijo), not(problematico(Hijo))) ).
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---forall---no-siempre-con-member.html b/wiki/articles/paradigma-logico---forall---no-siempre-con-member.html new file mode 100644 index 0000000000..c8127c869f --- /dev/null +++ b/wiki/articles/paradigma-logico---forall---no-siempre-con-member.html @@ -0,0 +1,356 @@ + + + + + + + + + + + Paradigma logico forall no siempre con member + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico forall no siempre con member +

    +
    + + + +
    +

    Partimos de la base que el forall corresponde a la idea “a todos los que les pasa A, les pasa B”.

    + +

    Por alguna razón, una proporción importante de las personas que están aprendiendo el paradigma lógico tienden a pensar que cada vez que quiero usar forall, tengo que tener la lista de los que les pasa A, entonces siempre que aparece forall como condición en una regla, va a ser de esta forma

    + +

       forall(member(E,ListaDeLosQueLePasaA), ...condiciones B sobre E...)

    + +

    Tal vez esto está relacionado con asimilar el forall con un for de (ponele) Pascal, que recorre la ListaDeLosQueLePasaA y verifica las condiciones del 2do argumento del forall para cada elemento de la lista.

    + +

    Esta forma de pensarlo no es correcta, veamos dos formas de ver la falla de razonamiento.

    + +
      +
    1. +

      no conviene pensar en el forall de acuerdo a “lo que hace”, sino a “cuándo se verifica”, o sea, si pongo forall como condición de una regla, cuando se va a cumplir.

      +
    2. +
    3. +

      el forall se cumple cuando cada respuesta a su primer argumento (que es una consulta) es respuesta del segundo argumento (que es otra consulta). Entonces, si uso forall poniendo member como primer consulta, lo que estoy diciendo es que todos los elementos de la lista cumplen con la 2da consulta, tiene el mismo resultado de “recorrer todos los elementos”, pero la idea es otra. Entonces, puedo usar la idea con member, o con cualquier condición que quiera.

      +
    4. +
    + +

    Un caso particular en el que se nota este razonamiento inadecuado es cuando se usa un findall seguido de un member, de esta forma

    + +

       findall(X, ...condiciones A sobre X..., ListaDeX), forall(member(E,ListaDeX), ...condiciones B sobre E...)

    + +

    es más directo, claro y correcto, usar el forall poniendo directamente “a E le pasa A” en lugar de “E está en la lista de los que les pasa A”, en Prolog:

    + +

       forall(...condiciones A sobre X..., ...condiciones B sobre E...)

    + +

    Veamos un ejemplo: quiero decir que un tipo es feliz si todos sus amigos son buena onda, tenemos los predicados amigos/2 y esBuenaOnda/1. Si quiero definir

    + +

      esFeliz(Pers)

    + +

    hay una condición “para todos los A pasa B” en donde calza justo un forall, “A” es “ser amigo de Pers” y “B” es “ser buena onda”.

    + +

    Si pienso que forall me sirve solamente para recorrer listas, entonces tengo que armar la lista de los amigos de Pers, y después fijarme para cada elemento que sea buena onda. En Prolog:

    + +

       esFeliz(Pers):-  +       findall(Amigo,amigos(Pers,Amigo),AmigosDePers),  +       forall(member(Chabon,AmigosDePers), esBuenaOnda(Chabon)).

    + +

    si entiendo que el primer argumento de forall puede ser cualquier consulta, pongo lo que entiendo de la definición, que es “ser amigo de Pers”. En Prolog

    + +

       esFeliz(Pers):- forall(amigo(Pers,Amigo), esBuenaOnda(Amigo)).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---functores.html b/wiki/articles/paradigma-logico---functores.html new file mode 100644 index 0000000000..c3b8177b94 --- /dev/null +++ b/wiki/articles/paradigma-logico---functores.html @@ -0,0 +1,392 @@ + + + + + + + + + + + Paradigma logico functores + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico functores +

    +
    + + + +
    +

    Los functores son individos que nos permiten agrupar otros individuos para formar una abstracción más compleja. Tienen un nombre y una aridad determinada, si alguno de estos elementos de un functor difiere con otro pasa a ser una abstracción diferente.

    + +

    Ejemplo

    + +
    vende(pepe, tornillo(5,parker)).
    +vende(tony, canilla(redonda,hierro,azul)).
    +
    + +

    Son valores, no predicados

    + +

    Los functores son valores, individuos.

    + +

    OK, son individuos compuestos, pero siguen siendo individuos. No son predicados, no tienen un valor de verdad.

    + +

    Si bien existe una similitud sintáctica entre ellos, la forma de uso es distinta, es por el contexto que Prolog decide si tratarlo como definición de un hecho, como consulta de un predicado o efectivamente como un functor.

    + +

    No tiene sentido consultar por functores, p.ej. hacer esta consulta

    + +

       ?- canilla(X,hierro,Y).

    + +

    sería lo mismo que preguntar

    + +

       ?- 1.

    + +

    Si hacemos la consulta

    + +

       ?- canilla(X,hierro,Y).

    + +

    Y no existe un predicado canilla/3, Prolog va a lanzar un error al intentar ejecutarlo como tal y no encontrar una definición.

    + +

    Si definimos lo siguiente en nuestra base de conocimientos:

    + +

       vende(pepe, canilla(Forma,Material,Color)). +   canilla(triangular,hierro,azul). +   canilla(triangular,porcelana,blanco).

    + +

    Y luego consultamos qué cosas vende pepe, la única respuesta que puede proveernos es basura con forma de canilla:

    + +

       ?- vende(pepe, CosaQueVende). +   CosaQueVende = canilla(_G9, _G10, _G11).

    + +

    En esas tres líneas de nuestra base de conocimientos tenemos predicado vende/2 que usa un functor canilla/3, y dos hechos para el predicado canilla/3. No hay ninguna relación entre ellos porque Prolog interpreta a los argumentos de los predicados como individuos. No va a intentar evaluar el functor canilla/3, lo va a tomar como un patrón para unificar en la consulta por pattern matching.

    + +

    Pregunta frecuente: ¿Cómo devolver functores?

    + +

    Antes que nada, el uso de la palabra “devolver”, marca que faltan entender cosas, porque la pregunta “cómo devuelvo” no tiene respuesta, no se puede devolver, no existe, es otro paradigma.

    + +

    Si lo comparamos con Pascal, es como si uno preguntara, ¿cómo hago para que sea inversible mi procedimiento?, no tendría sentido, ¿no?.

    + +

    No traten de “devolver” cosas, sino de establecer relaciones entre ellas.

    + +

    Una forma de arrancar es asumir que el parámetro me viene, entonces yo trato de describir cuáles son las condiciones que se tienen que cumplir.

    + +

    Una vez llegado a ese punto, si se necesita que sea inversible, analizamos cómo se van ligando las variables y si falta generar los valores posibles en algún caso.

    + +

    Por ejemplo, si pepe vende tornillos parker de todas las medidas disponibles, y sabemos que la medida es un número entre 1 y 5 podríamos hacer:

    + +

    vende(pepe, tornillo(Medida, parker)):- between(1, 5, Medida).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---generacion.html b/wiki/articles/paradigma-logico---generacion.html new file mode 100644 index 0000000000..90822ec46c --- /dev/null +++ b/wiki/articles/paradigma-logico---generacion.html @@ -0,0 +1,371 @@ + + + + + + + + + + + Paradigma logico generacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico generacion +

    +
    + + + +
    +

    El concepto de “generación” puede servir para acotar el conjunto de valores posibles para una variable, pero también para ligar la variable con un valor, ya que eso cambia la forma en la que se evalúan las siguientes consultas.

    + +

    Esto último tiene que ver con los problemas de inversibilidad, y los casos de uso se dividen en dos grandes grupos:

    + +

    a) Cuando la generación posibilita la siguiente consulta, por ejemplo:

    + +

    edad(Persona, E), E > 18.

    + +

    Necesito que E tenga un valor para poder evaluar E>18, si no se rompe.

    + +

    Ese sería el caso fácil, si rompe es un claro indicador de que el código no funciona para hacer esa clase de consultas, es fácil de identificar el problema.

    + +

    b) Cuando la semántica de la consulta es distinta a la que quiero, por ejemplo para la siguiente consulta, asumiendo que tenemos en nuestra base de conocimientos un predicado ocupa/3 que relaciona un jugador, un país y la cantidad de ejércitos que tiene en ese país:

    + +

          not((ocupa(Jugador, Pais, CantEjercitos), CantEjercitos > 3))

    + +
      +
    • +

      Si la variable Jugador llega ligada y Pais y CantEjercitos llegan libres, podría leerse como: “Dado este Jugador, no ocupa ningún país con más de 3 ejércitos”. Si Pais también llega ligada, la consulta que estamos haciendo sería: “No es cierto que este jugador ocupa este país con más de 3 ejércitos”.

      +
    • +
    • +

      En cambio, si Jugador y País están libres, se debería leer como: “No existe ningún jugador que ocupe algún país con más de 3 ejércitos”.

      +
    • +
    + +

    Entonces, no es que sea obligatorio generar, sino que el significado de la consulta es totalmente distinto, y dependiendo de lo que querramos hacer, hay que ligar previamente el jugador y/o el país o no.

    + +

    Veamos un ejemplo con el mismo dominio usando findall/3. Si nuestra intención es definir un predicado cantidadEjercitos/2 que relaciona un jugador con la cantidad total de ejércitos que tiene en todo el mundo y lo hacemos de la siguiente forma:

    + +

       cantidadEjercitos(Jugador,Cant):- +      findall(N,ocupa(Jugador,_,N),ListCants), +      sumlist(ListCants,Cant).

    + +

    Este predicado va a funcionar correctamente (dada una base de conocimientos con muchos jugadores que ocupan varios países) si la consulta realizada es individual respecto al jugador, pero no es totalmente inversible. Para que lo sea, tenemos que generar al jugador.

    + +

       cantidadEjercitos(Jugador,Cant):- +      jugador(Jugador), +      findall(N,ocupa(Jugador,_,N),ListCants), +      sumlist(ListCants,Cant).

    + +

    De esa forma podremos consultar:

    + +

     ?- cantidadEjercitos(Jugador, Cantidad).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---individuos-compuestos.html b/wiki/articles/paradigma-logico---individuos-compuestos.html new file mode 100644 index 0000000000..51a4839111 --- /dev/null +++ b/wiki/articles/paradigma-logico---individuos-compuestos.html @@ -0,0 +1,384 @@ + + + + + + + + + + + Paradigma logico individuos compuestos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico individuos compuestos +

    +
    + + + +
    +

    En contraposición a los átomos y los números, que son individuos simples, existen los individuos compuestos, estos son:

    + + + +

    Para acceder a los componentes de un individuo compuesto podemos usar Pattern Matching.

    + +

    En el caso de los functores, los componentes son los argumentos del functor. Si los quiero por separado, p.ej. si tenemos un functor de la forma canilla(Forma,Material,Color) y tenemos un predicado vende/2 que relaciona un local con una cosa que vende:

    + +

       vende(pepe,canilla(triangular,hierro,azul)).   

    + +

    podemos armar este predicado

    + +

       hayMaterial(Local,Mat):- vende(Local,canilla(_,Mat,_)).

    + +

    en donde estamos abriendo el functor canilla/3 mediante pattern matching y así unificando la variable Mat con el material de la canilla que se vende en el local.

    + +

    En el caso de las listas hay dos patrones básicos, una lista puede ser la lista vacía o con almenos un elemento. En caso de no ser la lista vacía los componentes son cabeza y cola, y la notación es

    + +

      [Cabeza | Cola]

    + +

    como la cola también es una lista, si la lista con la que quiero matchear espero que tenga al menos dos elementos puedo hacer:

    + +

      [Elem1 | [ Elem2 | Resto ] ]

    + +

    Probar p.ej. con esta consulta

    + +

      ?- [Elem1 | [ Elem2 | Resto ] ] = [a,e,i,o,u].

    + +

    Alternativamente se puede usar el patrón [Elem1, Elem2 | Resto] con el mismo objetivo, es un azúcar sintáctico para unificar dos variables con los primeros dos elementos de la lista.

    + +

    El caso típico para usar Pattern Matching sobre listas es en la recursividad.

    + +

    Combinando constructores de individuos compuestos

    + +

    Se pueden combinar estas dos formas de armar individuos compuestos, p.ej. con esta lista de functores.

    + +

      recorrido(linea19, [estacionTren(once), avenida(rivadavia), calle(salguero),  +                      calle(guardiaVieja), facultad(utnMedrano), calle(forest), estacionTren(chacarita)]).

    + +

    si quiero saber por qué estaciones de tren pasa una línea de colectivos, puedo definirlo así

    + +

      pasaPorEstacion(Linea,Estacion):- +     recorrido(Linea, Recorrido), member(estacionTren(Estacion),Recorrido).

    + +

    si consulto

    + +

      ?- pasaPorEstacion(linea19,Est).

    + +

    voy a obtener como respuestas

    + +

      Est = once; +  Est = chacarita; +  No

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---individuos-simples.html b/wiki/articles/paradigma-logico---individuos-simples.html new file mode 100644 index 0000000000..80f8e57262 --- /dev/null +++ b/wiki/articles/paradigma-logico---individuos-simples.html @@ -0,0 +1,355 @@ + + + + + + + + + + + Paradigma logico individuos simples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico individuos simples +

    +
    + + + +
    +

    Los primeros individuos con los cuales estaremos trabajando son los denominados simples (en contraposición a los individuos compuestos). Los que nos van a interesar para trabajar en general son los átomos y los números.

    + +

    Átomos

    + +

    Los átomos son valores que representan a una entidad indivisible. En el siguiente ejemplo podemos ver cómo se usan átomos para modelar la información:

    +
    padre(homero,bart).
    +padre(homero,lisa).
    +padre(homero,maggie).
    +padre(abe,homero).
    +
    + +

    Los átomos que se usan en el ejemplo son homero, bart, lisa, maggie y abe. Siempre que aparezca el átomo homero en mi programa me voy a estar refiriendo a la misma persona. Por eso puedo definir hermano/2 como:

    +
    hermano(H1, H2):- 
    +  padre(Padre, H1), 
    +  padre(Padre, H2), 
    +  H1 \= H2.
    +
    +

    Si los dos individuos que queremos relacionar con el predicado hermano/2 tienen al mismo padre, la relación se va a cumplir (usamos el \= para asegurarnos que una respuesta posible no sea H1=bart, H2=bart).

    + +

    Es importante notar que estos individuos no son strings

    +
    ?- length("homero",X).
    +X = 6
    +
    +?- length(homero,X).
    +No    <-- por principio de universo cerrado
    +
    + +

    Números

    + +

    Los números pueden usarse para lo mismo que en cualquier otro paradigma. Los podemos comparar, saber si uno es mayor que otro y usarlos para resolver operaciones aritméticas. Pero siendo que estamos en lógico y contamos con la idea de inversibilidad y múltiples respuestas también podemos hacer cosas como:

    +
    ?- between(3, 7, X).
    +X = 3 ;
    +X = 4 ;
    +X = 5 ;
    +X = 6 ;
    +X = 7 ;
    +No
    +
    +

    Algunas consideraciones que hay que tener con los operadores como el \=, el >, el + etc.. es que requieren que las variables utilizadas ya se encuentren ligadas. De lo contrario ocurrirá un error en tiempo de ejecución como este:

    +
    ?- 3 > A.
    +ERROR: Arguments are not sufficiently instantiated
    +
    +

    De la misma forma, el between que vimos recién sólo es inversible para el tercer argumento, los dos primeros que definen el rango deben ser valores concretos. Esto tiene sentido ya que las posibles respuestas serían infinitas si no se define un máximo y un mínimo.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---introduccion.html b/wiki/articles/paradigma-logico---introduccion.html new file mode 100644 index 0000000000..1b353c0ae9 --- /dev/null +++ b/wiki/articles/paradigma-logico---introduccion.html @@ -0,0 +1,429 @@ + + + + + + + + + + + Paradigma logico introduccion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico introduccion +

    +
    + + + +
    +

    El paradigma lógico se basa en la definición de reglas lógicas y es un paradigma declarativo así que si no lo leíste todavía te recomiendo leer antes sobre Declaratividad. En este artículo hablamos principalmente de la teoría del paradigma lógico, pero para los ejemplos tomamos como base el lenguaje Prolog

    + +

    Introducción: Silogismos

    + +

    ¿Cómo describir un problema usando la lógica? ¿Qué tipo de problema podemos describir?

    + +

    Comencemos con un ejemplo simple, seguramente muchos de ustedes lo habrán escuchado alguna vez:

    + +

    Sócrates es hombre

    + +

    Todos los hombres son mortales

    + +

    Luego… ¿qué podemos deducir de esto? Claro adivinaste, que Sócrates es mortal. De eso se trata la programación lógica, vamos a describir nuestro conocimiento en formas de reglas y vamos a permitir que otra cosa (el motor) se ocupe de procesar ese conocimiento y sacar conclusiones al respecto.

    + +

    ¿Y solito se da cuenta de las cosas? Más o menos, en realidad no podemos pedirle al motor que solamente se ponga a deducir y que nos diga a qué conclusión llega, hay que hacerle preguntas más concretas. Por ejemplo podemos preguntarle:

    +
      +
    • si socrates es mortal, y nos va a decir que sí
    • +
    • qué mortales conoce, y nos va a decir que socrates es mortal
    • +
    + +

    Esos son los dos tipos de preguntas básicas que el motor va a saber contestar, después vamos a bajar en detalle sobre esto.

    + +

    ¿Cómo lo bajamos a código?

    + +

    Programemos este mismo ejemplo en Prolog, en realidad es bastante simple:

    +
    hombre(socrates).
    +mortal(X):-
    +  hombre(X).
    +
    + +

    ¿Qué quiere decir esto?

    + +
      +
    • hombre(socrates) afirma que Sócrates es un hombre, o dicho de otra manera que socrates tiene la característica hombre. Es una afirmación que afecta únicamente a Sócrates y la llamamos un hecho, ya que es una declaración que no depende de nada para ser verdadera.
    • +
    • mortal(X):-hombre(X) es lo que llamamos una regla y se puede leer como: X es hombre ⇒ X es mortal. La regla es una implicación, el antecedente es hombre(X) y el consecuente es mortal(X). Esto quiere decir que para todo X que tenga la característica hombre se da que ese X también tiene la característica mortal (o más corto: todos los hombres son mortales).
    • +
    + +

    Fijate que socrates está en minúscula, mientras que la X aparece en mayúscula, ¿por qué? Los términos en minúscula se refieren a cosas particulares y las palabras en mayúscula son incógnitas (o variables).

    + +

    Eso se relaciona también con que la primera línea sea un hecho (porque habla de un individuo particular) y la segunda sea una regla (porque habla de todos los hombres).

    + +

    Pero la principal diferencia entre el hecho y la regla es que la regla tiene un antecedente (que se debe cumplir para que se cumpla la regla) y el hecho no, el hecho es verdadero siempre. En programas más complejos, a veces pasa que tenemos hechos que usan variables o reglas sobre individuos particulares.

    + +

    Los hechos me permiten definir por extensión el conjunto de individuos que tienen una característica. Las reglas me permiten hacer esa misma definición por comprensión.

    + +

    Un poco de teoría

    + +

    Si entendiste todo hasta acá, es momento de formalizar algunas cositas acerca del programa que hicimos. Antes que nada:

    + +
      +
    • La base de conocimiento se compone de cláusulas que definen predicados partiendo de los individuos de los que queremos hablar (para más detalles sobre estos términos, podemos pasar a ver algunas definiciones).
    • +
    • Un programa Prolog es una base de conocimiento.
    • +
    + +

    Para obtener resultados a partir de un programa, hacemos consultas individuales y existenciales.

    + +

    Universo Cerrado

    + +

    ¿Qué pasa si ahora quiero preguntar si Aristóteles es mortal?

    + +

    ?- mortal(aristoteles).

    + +

    Al ejecutar esa consulta, la secuencia de pasos del motor (simplificada) es la siguiente:

    + +
      +
    1. El motor buscará en la base de conocimientos las diferentes cláusulas del predicado mortal/1, en particular las que matcheen con mortal(aristoteles).
    2. +
    3. Al hacer esto encontrará una única regla: mortal(X):-hombre(X). Ergo, para probar que Aristóteles es mortal, deberá probar que es hombre.
    4. +
    5. Al intentar verificar si aristoteles es un hombre, es decir la consulta hombre(aristoteles).
    6. +
    7. Pero la única definición del predicado hombre es hombre(socrates), que no matchea con hombre(aristoteles).
    8. +
    9. La base de conocimientos no dice nada acerca de aristóteles, por lo tanto no se puede verificar que Aristóteles sea mortal.
    10. +
    + +

    En este momento aparece un concepto que llamamos principio de universo cerrado, que dice que el motor asume como falso todo lo que no pueda probar como verdadero, es decir que si al preguntarle si aristoteles es mortal, me va a contestar que no!

    + +

    Muchos entornos (tanto dentro del paradigma lógico como en otros muchos lugares) trabajan con este principio. Aunque no es la única forma de trabajar, es algo bastante frecuente dado que lo contrario es en general más complicado de implementar y de utilizar.

    + +

    ¿Cómo solucionar el problema?

    + +

    Agregando el hecho que indica que Aristóteles es un hombre:

    + +

    hombre(aristoteles).

    + +

    Si volvemos a hacer la misma consulta ahora vamos a tener el resultado esperado.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---inversibilidad.html b/wiki/articles/paradigma-logico---inversibilidad.html new file mode 100644 index 0000000000..c1eb1e5172 --- /dev/null +++ b/wiki/articles/paradigma-logico---inversibilidad.html @@ -0,0 +1,452 @@ + + + + + + + + + + + Paradigma logico inversibilidad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico inversibilidad +

    +
    + + + +
    +

    Definición

    + +

    La inversibilidad es una de las características distintivas del paradigma lógico, que no aparece en los paradigmas funcional ni objetos. Que un predicado sea inversible significa que los argumentos del mismo pueden usarse tanto de entrada como de salida. Es decir, no necesitás pasar el parámetro resuelto (un individuo concreto), sino que podés pasar una incógnita (variable sin unificar).

    + +

    Imaginate un predicado esNatural/1 que te dice si un número es natural:

    +
    esNatural(1)
    +Yes
    +
    +esNatural(-2)
    +No
    +
    +

    Cuando un predicado es inversible, también podés hacer otro tipo de consultas, poniendo una incógnita en el parámetro en lugar de un valor:

    +
    esNatural(N)
    +N=1;
    +N=2;
    +N=3;
    +etc...
    +
    +

    Esta característica es exclusiva del paradigma lógico, ya que está basado en el concepto de relación matemática (y no en el de función, donde siempre íbamos de un dominio a una imagen).

    + +

    La inversibilidad no tiene que ver solamente con que “dé error” si pasamos una incógnita donde no podíamos hacerlo, muchas veces lo que pasa es que -sin dar error- se comporta incorrectamente o de forma distinta a la que uno esperaría. En ese caso también decimos que no es inversible.

    + +

    Ejemplos

    + +

    Veamos este programa

    +
    vive(ruben,lanus).
    +vive(ana,lanus).
    +vive(laura,boedo).
    +vive(susi,bernal).
    +
    +sonVecinos(P1,P2):- 
    +  vive(P1,B), 
    +  vive(P2,B), 
    +  P1 \= P2.
    +esDelSur(P):- vive(P,lanus).
    +esDelSur(P):- vive(P,bernal).
    +
    + +

    Todos los predicados que aparecen son totalmente inversibles, porque puedo hacer consultas con cualquier combinación de valores e incógnitas. ¿Qué quiere decir esto? Mirá todas las consultas que se pueden hacer

    +
    ?- vive(ruben,B).
    +?- vive(P,lanus).
    +?- vive(ruben,boedo).   % responde que no
    +?- vive(P,B).
    +
    +

    y lo mismo para sonVecinos

    +
    ?- sonVecinos(ruben,X).
    +?- sonVecinos(X,ruben).
    +?- sonVecinos(ana,ruben).   % responde que sí
    +?- sonVecinos(X,Y).
    +
    +

    para esDelSur/1 hay menos combinaciones, porque tiene un sólo argumento

    +
    ?- esDelSur(susi).     % ¿qué te parece que responde?
    +?- esDelSur(P).        % idem
    +
    +

    Observar que cada predicado tiene una definición sola, no tengo que pensar en distintas definiciones para cubrir las distintas combinaciones entre valores e incógnitas. Para sonVecinos/2, no tengo que armar una regla por si me consultan con dos valores, una distinta por si me consultan con dos incógnitas, etc..

    + +

    OJO - inversible no es lo mismo que simétrico

    + +

    Sigamos con el programa anterior. Ya vimos que los tres predicados son inversibles.

    + +

    Ahora bien, ¿son simétricos?

    + +

    Empecemos pensando qué quiere decir “simétricos”. Es como una relación simétrica de las de teoría de conjuntos: una relación R es simétrica si siempre que pasa aRb, también pasa bRa.

    + +

    Entonces, el predicado vive/2, ¿es simétrico? Veamos. Si consulto

    + +

    ?- vive(ruben,lanus).

    + +

    responde que sí, o sea, ruben / vive / lanus. En el esquema aRb, es

    + +
      +
    • a: ruben
    • +
    • R: vive
    • +
    • b: lanus
    • +
    + +

    O sea que bRa sería

    + +

    ?- vive(lanus,ruben).

    + +

    y la respuesta de esto claramente va a ser no.

    + +

    Entonces el predicado vive/2 no es simétrico. Pero ya vimos que sí es inversible, porque

    + +
      +
    • inversible quiere decir “puedo hacer consultas con cualquier combinación de valores e incógnitas”.
    • +
    • y no quiere decir “si invierto los argumentos da las mismas respuestas”. Esto es simetría.
    • +
    + +

    En cambio, sonVecinos/2 es esperable que se verifique para el mismo par de individuos en cualquier orden. A su vez, por como está definido es inversible, pero no tiene nada que ver una cosa con la otra.

    + +

    Observar que la noción de simetría sólo se aplica a predicados de 2 argumentos (para esDelSur/1 ¿cómo sería “ser simétrico”? No tiene sentido), mientras que la de inversibilidad se aplica a cualquier predicado.

    + +

    Resumen ejecutivo: ojo al piojo, inversibilidad es una cosa muy distinta a simetría, no confundirse. Si no queda claro, consulte con su docente amigo. Lo que nos va a interesar en la materia es el concepto de inversibilidad.

    + +

    ¿Cómo hacés que un predicado sea inversible?

    + +

    En principio, todo predicado es inversible salvo que caiga en un caso de no-inversibilidad.

    + +

    Estos casos tienen que ver con las submetas de un predicado que requieren variables ligadas, en estas cosas es que hay que fijarse para saber qué hace falta generar.

    + +

    Por ejemplo: cuando una de las componentes de un predicado es un not/1 , necesitás que el predicado que le mandás tenga sus parámetros unificados. Cuando usás una evaluación matemática (ej: X is N \* 2), necesitás que lo de la derecha (la N) esté unificado.

    + +

    ¿Cuál sería el uso?

    + +

    Inherentemente es más potente que una función, ya que te permite encontrar todos los valores para los cuales una relación se cumple (y esto tiene que ver también con la idea de múltiples resultados…).

    + +

    La ventaja inmediata es que te permite más formas de usarlo, lo típico: puedo preguntar si un alumno aprobó, o todos los alumnos que aprobaron, etc.

    + +

    Luego podría aparecer otra ventaja y es que si todos mis predicados son inversibles, eso de verdad me permite usarlos sin pensar nada nada nada en la secuencia y me da más lugar a sólo declarar el conocimiento. Y eso le da una potencia más grande a mi lenguaje/paradigma/entorno de programación.

    + +

    (Igual no debe entenderse de lo último que todos los predicados que hago deben ser inversibles. )

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---listas.html b/wiki/articles/paradigma-logico---listas.html new file mode 100644 index 0000000000..037a867dcf --- /dev/null +++ b/wiki/articles/paradigma-logico---listas.html @@ -0,0 +1,741 @@ + + + + + + + + + + + Paradigma logico listas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico listas +

    +
    + + + +
    +

    Motivación

    + +

    Si nuestra base de conocimiento es

    + +
    padre(homero,bart).
    +padre(homero,maggie).
    +padre(homero,lisa).
    +
    + +

    Vimos varias consultas posibles

    + +
    %Es cierto que homero es padre de bart?
    +?- padre(homero,bart).
    +Yes
    +%Es cierto que homero es papá?
    +?- padre(homero,_).
    +Yes
    +%Quienes son los padres de bart?
    +?- padre(P,bart).
    +P = homero
    +%Quienes son los hijos de homero?
    +?- padre(homero,H).
    +H = bart;
    +...
    +
    + +
    %Quienes son padre e hijo?
    +?- padre(X,Y).
    +X = homero
    +Y = bart;
    +etc.
    +
    + +

    Pero a pesar de esta gran gama de consultas hay ciertas preguntas que se vuelven complicadas o imposibles. Vamos a tomar como ejemplo la siguiente pregunta: ¿Cuántos hijos tiene homero?.

    + +

    En el estado actual de las cosas tenemos que hacer la consulta

    + +
    ?- padre(homero,H).
    +H = bart;
    +H = lisa;
    +H = maggie;
    +No
    +
    + +

    Contamos la cantidad de respuestas, en este caso los posibles valores de H y obtenemos la respuesta … 3. Ahora bien, esto es impracticable cuando el número de respuestas es alto y además no responde a nuestra pregunta de forma directa.

    + +

    Pensemos en predicados e individuos y definamos un predicado que relacione lo que nos interesa … una persona y su cantidad de hijos. Dicho predicado puede llamarse cantidadDeHijos/2.

    + +
    ?- cantidadDeHijos(homero,C).
    +C = 3
    +
    + +

    Perfecto, ya tenemos definido nuestro objetivo ahora definamos el predicado a través de una regla (lo quiero hacer por comprensión porque quiero que me sirva para cualquier persona, no solo homero)

    + +
    cantidadDeHijos(P,Cantidad) :- ... .
    +
    + +

    Para resolver esto volvamos un poco para atrás. En el mundo del paradigma lógico ¿qué es lo que da 3? La cantidad de respuestas de la consulta .

    + +

    Entonces lo que nos gustaría hacer es tener en un solo lugar todas las respuestas a la consulta para después contar todos los posibles valores de H pero todavía no sabemos cómo hacer eso así que imaginemos que por el momento es magia.

    + +

    El conjunto como un individuo

    + +

    Sin importar como obtenemos esas respuestas las queremos tener identificadas en un solo lugar, en un solo individuo … un individuo compuesto que representa un conjunto!

    + +

    En el caso de homero ese conjunto va a ser .

    + +

    A este tipo de individuo que representa conjuntos lo vamos a llamar lista y se encierra entre corchetes () donde cada elemento del conjunto se separa por coma ().

    + +

    En nuestra definición del predicado vamos a definir una variable Hijos que va representar a dicho conjunto, pero a nosotros no nos interesa el conjunto de hijos sino la cantidad de elementos que tiene ese conjunto …

    + +

    Una vez hecha la magia, lo que necesitamos es un predicado que relacione a un conjunto con su cantidad de elementos y eso ya viene con prolog. Ese predicado se llama .

    + +
    cantidadDeHijos(P,Cantidad) :- 
    +    acá va la magia que le da valor a la variable Hijos,
    +    length(Hijos,Cantidad).
    +
    + +

    Nos falta hacer la magia!

    + +

    ¿Cómo obtener todas las respuestas ‘juntas’?

    + +

    Si tenemos una forma de obtener múltiples respuestas a una consulta (en este caso, todos los H que son respuesta de la consulta padre(P,H) cuando P es por ejemplo homero), y lo que queremos es que todas esas respuestas estén juntas en una lista, hay un predicado en Prolog que hace exactamente eso:

    + +
    findall(UnIndividuo,Consulta,Conjunto)
    +
    + +

    Donde:

    + +
      +
    • +

      normalmente es una variable que se usa en la Consulta

      +
    • +
    • +

      es una lista con todos los individuos que se encontraron al consultar la Consulta

      +
    • +
    + +

    Entonces:

    + +

    findall es un predicado que relaciona a una consulta con el conjunto (lista) de sus respuestas.

    + +

    El otro parámetro me permite indicar qué es lo que me interesa para completar la lista. Volviendo a nuestro ejemplo

    + +
    cantidadDeHijos(P, Cantidad) :- 
    +    findall(H, padre(P,H), Hijos),
    +    length(Hijos, Cantidad).
    +
    + +

    Con esta definición nuestro objetivo se cumple

    + +
    ?- cantidadDeHijos(homero,C).
    +C = 3
    +
    + +

    Observamos que la variable de la cláusula que define cantidadDeHijos llega ligada al findall, por lo tanto la consulta que está adentro (el 2do parámetro) queda que efectivamente tiene 3 respuestas.

    + +

    Inversibilidad del predicado findall

    + +

    Ahora bien, agregemos algunos hechos a la base de conocimiento

    + +
    padre(homero,bart).
    +padre(homero,maggie).
    +padre(homero,lisa).
    +padre(abraham,homero).
    +padre(abraham,herbert).
    +
    + +

    Y pensemos en otra consulta

    + +
    ?- cantidadDeHijos(P,C).
    +C = 5.
    +
    + +

    No funciona como esperábamos, ¿a qué se debe?

    + +

    Debemos mirar la consulta que se está realizando en el findall (el 2do parámetro): . Si pensamos cuántas respuestas tiene esa pregunta veremos que ¡efectivamente son 5!

    + +
    %Quienes son padre e hijo?
    +?- padre(P,H).
    +P = homero,
    +H = bart ;
    +P = homero,
    +H = maggie ;
    +P = homero,
    +H = lisa ;
    +P = abraham,
    +H = homero ;
    +P = abraham,
    +H = herbert.
    +
    + +

    En el findall/3 como primer parámetro dijimos que nos interesa solamente la variable H de cada respuesta, e Hijos será un conjunto de esos H. Por lo tanto Hijos es la lista [bart,maggie,lisa,homero,herbert] que tiene 5 elementos (la respuesta a nuestra consulta).

    + +

    Un findall totalmente inversible: Generación

    + +

    El problema está en la consulta de adentro del findall, no queremos preguntar “¿Quienes son padre e hijo?” sino “¿Quienes son hijos de P?” (risas) y para preguntar eso P debe llegar ligada al findall, para poder preguntar por los hijos de una persona en particular.

    + +

    Ahora tenemos que averiguar cómo ligar a P, y para eso hay que pensar cuáles serían los posibles P que nos interesan. Una respuesta sencilla es pensar que queremos que P sea una persona, entonces podríamos agregar al antecedente la restricción: .

    + +

    (También se podría usar el predicado padre/2 en lugar de persona/1, analizamos la diferencia entre ambos en el próximo apartado.)

    + +
    cantidadDeHijos(P,Cantidad) :-
    +    persona(P), % Generacion, asi la variable P llega ligada al findall
    +    findall(H,padre(P,H),Hijos),
    +    length(Hijos,Cantidad).
    +
    + +

    Lo que logramos al hacer que P llegue ligada al findall es que el predicado cantidadDeHijos/2 sea totalmente inversible. A esta técnica la denominamos generación.

    + +

    Dos formas distintas de generación

    + +

    Dijimos que en realidad hay dos formas de determinar cuáles son todos los P que me interesan:

    + +
      +
    1. Una forma es decir que P es una persona, entonces podríamos poner:
    2. +
    3. Por el otro podemos pensar que P tiene que ser padre, entonces surge la opción: . (Me interesa que sea padre y no me importa en principio cuáles son sus hijos.
    4. +
    + +

    ¿Qué pasaría si usamos en lugar de como generador?

    + +
    cantidadDeHijos(P,Cantidad) :-
    +    padre(P,_), %Generacion, asi la variable P llega ligada al findall
    +    findall(H,padre(P,H),Hijos),
    +    length(Hijos,Cantidad).
    +
    + +

    La diferencia la vamos a encontrar si hacemos la consulta:

    + +
    ?- cantidadDeHijos(bart,C).
    +
    + +

    Con la solución propuesta en el apartado anterior nos dice que bart tiene cero hijos:

    + +
    ?- cantidadDeHijos(bart,C).
    +C = 0
    +
    + +

    Con la segunda posibilidad, bart no es una posible respuesta para (porque no es padre de nadie). Entonces lo que voy a obtener es:

    + +
    ?- cantidadDeHijos(bart,C).
    +No
    +
    + +

    En este caso consideramos que es más saludable un 0 que un No. Independientemente de eso, lo que debe quedar de todo esto es que las distintas formas de generar nos pueden dar diferentes resultados como respuesta y hay que elegir qué queremos.

    + +

    Una pregunta adicional que podría surgir es: ¿qué pasa si no tenemos el predicado persona? Bueno, habrá que agregarlo a la base de conocimientos, y para ello tenemos dos posibilidades:

    + +

    Por extensión:uno por uno enumerando cada persona (un hecho para cada persona:

    + +
    persona(bart).
    +persona(lisa).
    +... etc.
    +
    + +

    Por comprensión:con una regla descubrir quiénes podemos considerar persona a partir de la información que ya tenemos. Una forma de hacer eso sería:

    + +
    persona(Papa) :- padre(Papa,_).
    +persona(Hijo) :- padre(_,Hijo).
    +
    + +

    Es decir, el que es padre de alguien es una persona, y el que es hijo también.

    + +

    Haciendo consultas más heavies

    + +

    En el segundo parámetro del findall se pueden poner cualquier tipo de consulta, no es necesario que solo 1 predicado esté involucrado.

    + +

    findall(X,(p(X),q(X),r(X),…,s(X)), Xs)

    + +

    Hay que encerrarla entre paréntesis para no cambiar la aridad de findall que es tres (3).

    + +

    Ejemplo

    + +

    Si queremos hacer un predicado que me diga cuantos hijos pibes tiene una persona podemos hacer esto

    + +

    Los X que me interesan son los que cumplen la consulta (padre(P,H),esPibe(H))

    + +
    cuantosPibes(Persona,Cant) :- 
    +     persona(Persona),
    +     findall(H,(padre(Persona,H),esPibe(H)),Pibes),
    +     length(Pibes,Cant).
    +
    + +

    Otro ejemplo usando listas

    + +
    interseccion(Xs,Ys,Zs) :-
    +    findall(E,(member(E,Xs),member(E,Ys)),Zs).
    +
    + +

    Usando individuos compuestos en el primer parámetro del findall

    + +

    En ciertas situaciones nos interesa tener una lista de individuos que hasta el momento no existían en nuestro programa o que no están presentes explícitamente en la consulta (o sea, en el 2do parámetro del findall).

    + +

    Ejemplo:

    + +

    Imagínense que tenemos un programa en donde se define el predicado puntaje/2 que relaciona a un equipo con la cantidad de puntos que tiene. Un requerimiento bastante usual en un programa de este estilo, es conocer la tabla de posiciones que se puede ver como un conjunto de individuos o sea una lista en donde cada individuo que la compone es un equipo con su cantidad de puntos.

    + +
    ?- findall( ???? , puntaje(Equipo,Cant), Tabla ).
    +
    + +

    La pregunta a responder es qué ponemos en ????. Necesitamos definir un individuo que está compuesto por otros 2 individuos (Equipo y Cant). Para hacer esto nada mejor que un functor (un indivudo compuesto de tamaño fijo), le inventamos un nombre por ejemplo ptos

    + +
    ?- findall( ptos(Equipo,Cant) , puntaje(Equipo,Cant) , Tabla )
    +
    + +

    Recuerden:

    + +
      +
    • ptos es un functor no un predicado
    • +
    • puntaje es un predicado no un functor
    • +
    • Tabla es una lista de functores ptos que verifican la consulta que está como segundo parámetro del findall
    • +
    + +

    Sacando los repetidos con distinct

    + + + +

    Recursividad Con Listas

    + + + +

    Errores comunes

    + +

    findall y member

    + +

    El error más común para quienes no están acostumbrados a pensar en términos del paradigma es armar listas cuando no son necesarias para la resolución del problema. Esto se pone en evidencia por el uso del findall seguido por un member sobre la lista resultante. El findall arma listas, el member las desarma… son operaciones inversas!

    + +

    Por ejemplo, si quiero saber quiénes son los hijos de homero puedo consultar padre(homero,Hijo). Resolver esto como:

    + +
    ?- findall(H, padre(homero,H), Hijos), member(Hijo,Hijos).
    +
    + +

    es no estar entendiendo la forma de pensar.

    + +

    Si bien este primer ejemplo puede parecer obvio, hay casos en los cuales no es tan evidente, por ejemplo cuando se arma una lista de los que cumplen CONDICION con el predicado A y el predicado B consulta A y luego se obtienen los elementos con member.

    + +

    Siguiendo el ejemplo anterior de los hijos pibes, podemos mostrar el problema anterior de esta forma:

    + +
    hijosPibes(P,Pibes) :- persona(P),
    +     findall(H,(padre(P,H),esPibe(H)),Pibes).
    +esHijoPibe(Persona,Hijo) :-
    +     hijosPibes(Persona,Pibes),
    +     member(Hijo,Pibes).
    +
    + +

    En ese caso todo lo que necesitábamos era consultar por existencia quién cumple CONDICION, y si todavía nos interesa hijosPibes/2 podríamos hacer los siguientes cambios:

    + +
    hijosPibes(P,Pibes) :- persona(P),
    +     findall(Hijo,esHijoPibe(P,Hijo),Pibes).
    +esHijoPibe(Persona,Hijo) :-
    +     padre(Persona,H),
    +     esPibe(H).
    +
    + +

    En este caso fue simple porque B modelaba directamente CONDICION, pero bien podría pasar que nos esté faltando una abstracción para modelar CONDICION, que podemos solucionar definiendo otro predicado C y modificando los predicados A y B para que usen C.

    + +

    findall y length

    + +

    Uno de los usos más comunes de findall tiene como objetivo saber cuántos individuos cumplen una determinada condicion, como en el ejemplo visto anteriormente de cantidadDeHijos/3. Sin embargo hay casos en los cuales pensamos la solución a un problema básico en término de cantidad de respuestas, lo cual disminuye la declaratividad de la solución. Veamos un par de ejemplos:

    + +
     esPadre(Persona) :- persona(Persona),
    +      findall(Hijo, padre(Persona, Hijo), Hijos),
    +      length(Hijos, CantidadDeHijos),
    +      CantidadDeHijos >= 1.
    +
    + +
     noTieneHijos(Persona) :- persona(Persona),
    +      findall(Hijo, padre(Persona, Hijo), Hijos),
    +      length(Hijos, 0).
    +
    + +

    Estos dos predicados podrían definirse sin uso de listas, y no sólo eso sino que la solución de ambos es mucho más sencilla. En ambos casos debería simplemente trabajar con la idea de existencia, ya sea afirmándola o negándola, o sea:

    + +
     esPadre(Persona) :- padre(Persona,_).
    +
    + +
     noTieneHijos(Persona) :- persona(Persona),
    +      not(padre(Persona, _)).
    +
    + +

    Caso “existe más de un”

    + +

    Un problema común es saber si hay más de un individuo que cumple una condición. Si alguien tiene más de un hijo, por ejemplo. Eso lo podemos saber así:

    + +
     tieneMasDeUnHijo(Persona) :- persona(Persona),
    +      findall(Hijo, padre(Persona, Hijo), Hijos),
    +      length(Hijos, CantidadDeHijos),
    +      CantidadDeHijos > 1.
    +
    + +

    Hay un problema nuevamente con la declaratividad, y con la manera de pensar lógicamente. Si le damos una vuelta de tuerca, podemos resolver este ejercicio sin necesidad de armar una lista y contar.

    + +

    Esto se logra pensando así: tengo más de un hijo si existen dos hijos diferentes.

    + +
     tieneMasDeUnHijo(Persona):-
    +      padre(Persona,Hijo1),
    +      padre(Persona,Hijo2),
    +      Hijo1 \= Hijo2.
    +
    + +

    ¡Es mucho más directo! Y respeta mejor las ideas del paradigma.

    + +

    Caso “existe sólo un”

    + +

    Este es para pensar:

    + +
     tieneSoloUnHijo(Persona) :- persona(Persona),
    +      findall(Hijo, padre(Persona, Hijo), Hijos),
    +      length(Hijos, 1).
    +
    + +

    ¿No podría hacerlo de otra forma?

    + +

    Alguien tiene un sólo hijo si:

    + +
      +
    • Existe al menos un hijo, y
    • +
    • No existe más de un hijo
    • +
    + +

    (sale usando lo explicado arriba)

    + +

    findall y forall

    + +

    Y otro caso típico de mal uso de findall y member aparece al tratar de usar el forall.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---multiples-respuestas.html b/wiki/articles/paradigma-logico---multiples-respuestas.html new file mode 100644 index 0000000000..1241e386a8 --- /dev/null +++ b/wiki/articles/paradigma-logico---multiples-respuestas.html @@ -0,0 +1,360 @@ + + + + + + + + + + + Paradigma logico multiples respuestas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico multiples respuestas +

    +
    + + + +
    +

    Al hacer una consulta existencial se puede obtener más de una respuesta. Esto se debe a que estamos trabajando con relaciones, no con funciones. Las funciones son un caso particular de relación que se caracterizan por cumplir con unicidad (para cada valor de entrada hay una única salida), mientras que las relaciones no tienen esa restricción.

    + +

    P.ej. si Pedro tiene como primos a Lucía, Alan y Guido; entonces la relación “ser primos” relaciona a Pedro con tres personas distintas:

    +
    primo(pedro,lucia).
    +primo(pedro,alan).
    +primo(pedro,guido).
    +
    + +

    Entonces si consulto quién es un posible primo de Pedro, lo que debe pasar es que se obtengan tres respuestas independientes entre ellas: una respuesta por cada primo que tenga Pedro.

    +
    ?- primo(pedro,Primo).
    +   Primo = lucia;
    +   Primo = alan;
    +   Primo = guido
    +
    + +

    En funcional no tendría sentido que para la función primo existan 3 respuestas para el valor Pedro, dado que no cumpliría con la propiedad de unicidad de las funciones. La única forma de responder que tanto Lucía, Alan y Guido son primos de Pedro es mediante el uso de valores compuestos para representar al conjunto que incluye a todos ellos.

    + +

    Ahora, si quisiéramos resolver un problema donde esperamos que cada individuo se relacione con un único valor, eso debe asegurarse dentro de la lógica del predicado.

    + +

    Pongamos un ejemplo sencillo para analizar: supongamos que queremos definir un predicado que relacione a un valor consigo mismo, salvo que ese valor sea el 0, en cuyo caso se lo debe relacionar con el número 1. No alcanzaría sólo con explicitar mediante un hecho que el 0 se relaciona con el 1 y luego generalizar lo que pasa con los otros valores de esta forma de esta forma:

    +
    p(0, 1).
    +p(X, X).
    +
    +

    Ya que si consultamos:

    +
    ?- p(0, Valor).
    +Valor = 1;
    +Valor = 0
    +
    +

    Para que la única respuesta posible sea 1, tenemos que asegurar que el caso general excluya al 0, lo cual puede lograrse de la siguiente forma:

    +
    p(0, 1).
    +p(X, X) := X \= 0.
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---negacion.html b/wiki/articles/paradigma-logico---negacion.html new file mode 100644 index 0000000000..04fb3f89d7 --- /dev/null +++ b/wiki/articles/paradigma-logico---negacion.html @@ -0,0 +1,481 @@ + + + + + + + + + + + Paradigma logico negacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico negacion +

    +
    + + + +
    +

    El predicado de orden superior más simple, y a la vez muy utilizado, es el not/1, que representa una negación. Si P es una proposición, entonces not(P) es una proposición que niega el valor de verdad asumido para P. Así, la negación de algo falso se toma por verdadera, y la negación de algo con valor cierto, se toma como falso.

    + +

    Ejemplos

    + +

    Consultas Individuales

    + +

    Supongamos lo siguiente:

    + +
    esMalo(feinmann). 
    +esMalo(hadad). 
    +esMalo(echecopar).
    +
    + +

    Y miremos los resultados de las siguientes consultas:

    + +
    ?- esMalo(hadad).
    +true
    +?- not(esMalo(hadad)).
    +false
    +?- esMalo(bambi).
    +false
    +?- not(esMalo(bambi)).
    +true
    +
    + +

    Ahora, miremos ésto:

    + +
    ?- esMalo(34).
    +false
    +
    + +

    ¡Claro que no es malo! ¡El 34 no lastimaría una mosca! Porque éste paradigma se basa en el concepto de Universo Cerrado. (Si no está en la base, es falso). Entonces, la siguiente consulta da verdadero:

    + +
    ?- not(esMalo(34)).
    +true
    +
    + +

    Consultas Existenciales ó Variables

    + +

    Recordemos cuál es el significado de la siguiente consulta:

    + +

    ?- esMalo(_).

    + +

    Así, con la variable anónima, estoy preguntando si existe un malo. Bueno, eso es cierto:

    + +
    ?- esMalo(_).
    +true
    +
    + +

    Ahora bien, veamos qué sucede si preguntamos si es cierto que “no existe un malo”

    + +
    ?- not(esMalo(_)).
    +false
    +
    + +

    Por último, ¿se podrá usar una variable que no sea la variable anónima dentro de una negación?

    + +

    Para responder a eso vamos a tener que hablar sobre inversibilidad.

    + +

    Inversibilidad

    + +

    Agreguemos lo siguiente al ejemplo:

    + +
    esPersona(feinmann). 
    +esPersona(hadad). 
    +esPersona(echecopar).
    +esPersona(bambi).
    +esPersona(fer).
    +esPersona(lucas).
    +
    +esBueno(Persona):- 
    +  not(esMalo(Persona)).
    +
    + +

    Problema

    + +

    Veamos el resultado de la siguiente consulta:

    + +
    ?- esBueno(lucas).
    +true.
    +?- esBueno(fer).
    +true.
    +
    + +

    Y ahora tratemos de preguntar si existe algún bueno (claro que existen!):

    + +
    ?- esBueno(X).
    +false.
    +
    + +

    ¿¿Qué pasó?? ¿No debería ser capaz de decirnos quiénes son buenos?

    + +

    Interpretación

    + +

    Mi regla dice que se cumple esBueno(X), si se cumple not(esMalo(Persona)).

    + +

    Sabiendo que la variable anónima es igual que cualquier otra variable, sólo que la usamos cuando no nos interesa conocer qué individuo hace que se cumpla la consulta, éstas dos consultas tienen el mismo valor de verdad, que para nuestra base de conocimientos sería verdadero ya que existe alguien que es malo:

    + +
    ?- esMalo(_).
    +?- esMalo(X).
    +
    + +

    Entonces, la siguiente consulta (equivalente a esBueno(X)) dará falso:

    + +
    ?- not(esMalo(X)).
    +false.
    +
    + +

    Porque estoy preguntando si es cierto que “no existe alguien malo”.

    + +

    Normalmente si usamos una variable no anónima, Prolog tratará de darnos ejemplos que hacen verdadera esa consulta. Pero en el caso de la negación, es imposible para el motor encontrar ejemplos de individuos que satisfagan la consulta, porque son infinitos! Por ejemplo, el 34 no es malo…

    + +
    ?- esBueno(34).
    +true.
    +
    + +

    Solución

    + +

    Entonces… ¿Qué hacemos?

    + +

    Generamos.

    + +

    Generar es agregar una condición que sea inversible antes del not, para que las variables lleguen ligadas al mismo. De ésta manera, transformamos la consulta dentro del not que podía llegar a ser una consulta existencial en una consulta individual, que funcionan como nosotros esperamos (Leer más ariba).

    + +
    esBueno(Persona) :-
    +  esPersona(Persona), 
    +  not(esMalo(Persona)).
    +
    + +

    Y así podemos consultar si “existe un bueno”, y tener también ejemplos de buenos.

    + +
    ?- esBueno(X).
    +X = bambi;
    +X = fer;
    +X = lucas.
    +
    + +

    Para más información sobre inversibilidad y generación, visitar el artículo Paradigma Lógico - inversibilidad

    + +

    Además, nuestro nuevo predicado esBueno se va a comportar distinto que antes ante esta consulta individual:

    + +
    ?- esBueno(34).
    +false.
    +
    + +

    Si bien el número 34 nos gusta mucho, sería conceptualmente incorrecto aceptar que fuera bueno, ya que nuestro dominio trabaja con personas, y es sobre ellas que, en éste caso, queremos verificar la propiedad de ser buenas. Con el agregado que hicimos no sólo resolvimos el problema de las consultas existenciales, sino que además sirvió para acotar el dominio de aquellos que pueden ser buenos.

    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico---un-poco-de-nomenclatura.html b/wiki/articles/paradigma-logico---un-poco-de-nomenclatura.html new file mode 100644 index 0000000000..02bc88c5ab --- /dev/null +++ b/wiki/articles/paradigma-logico---un-poco-de-nomenclatura.html @@ -0,0 +1,473 @@ + + + + + + + + + + + Paradigma logico un poco de nomenclatura + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico un poco de nomenclatura +

    +
    + + + +
    +

    Cuando describimos los elementos de un programa en lógico (ya sea para su definición como su uso) vamos a usar los siguientes términos:

    + +
      +
    1. Individuo +
        +
      • Individuo simple +
          +
        • Átomo
        • +
        • Número
        • +
        +
      • +
      • Individuo compuesto +
          +
        • Lista
        • +
        • Functor
        • +
        +
      • +
      +
    2. +
    3. Predicado +
        +
      • Propiedad
      • +
      • Relación
      • +
      +
    4. +
    5. Cláusula +
        +
      • Hecho
      • +
      • Regla
      • +
      +
    6. +
    7. Consulta +
        +
      • Individual
      • +
      • Existencial
      • +
      +
    8. +
    + +

    A continuación mostramos un programa sencillo (la base de conocimiento) como para tener de referencia e identificar cuándo usamos cada uno de estos términos.

    + +
    hombre(socrates).
    +hombre(solon).
    +hombre(pericles).
    +hombre(arquimedes).
    +mortal(X):-
    +  hombre(X).
    +ciudad(atenas).
    +ciudad(siracusa).
    +vive(socrates,atenas).
    +vive(solon,atenas).
    +vive(pericles,atenas).
    +vive(arquimedes,siracusa).
    +nacio(solon,-634).
    +nacio(pericles,-495).
    +nacio(arquimedes,-287).
    +sonConciudadanos(P1,P2):- 
    +  vive(P1,C), 
    +  vive(P2,C).
    +
    + +

    Individuos

    + +

    Los individuos son aquellas cosas sobre las que versa el conocimiento que queremos expresar. En el ejemplo aparecen varios individuos: socrates, atenas, solon, arquimedes, siracusa, -634, -287. Individuo es cualquier entidad acerca de la cual nos interese estudiar sus características o sus relaciones con otros individuos. P.ej. si hiciéramos un sistema para controlar correlatividades entre las materias de la facultad, tendríamos un individuo para representar cada materia. Los individuos se dividen en

    + + + +

    Predicados

    + +

    Los predicados son las cosas que queremos decir (o predicar, je) acerca de los invividuos. En este ejemplo los predicados que aparecen se llaman mortal, hombre, vive, nacio, sonConciudadanos.

    + +

    A la cantidad de parámetros que lleva cada predicado la llamamos su aridad. En el ejemplo, los predicados hombre, mortal y ciudad tienen aridad 1, mientras que vive y sonConciudadanos tienen aridad 2. A partir de su aridad podemos separar los predicados en:

    + +
      +
    • Propiedades : Son los predicados de aridad 1, que expresan características de individuos. Por ejemplo, ser mortal es una propiedad.
    • +
    • Relaciones : Son los predicados de aridad mayor a 1, que expresan relaciones entre individuos. Por ejemplo, saber dónde vive alguien es una relación entre una persona y una ciudad.
    • +
    + +

    Usualmente haremos referencia a un predicado en particular, no sólo mediante su nombre sino también su aridad (por ejemplo hombre/1), ya que podrían haber predicados con el mismo nombre pero distinta aridad y serían totalmente independientes entre ellos.

    + +

    Volviendo al ejemplo del sistema de correlatividades, seguramente tendría un predicado que relacione cada alumno con cada materia que cursó, y otro que indique la correlatividad entre dos materias relacionando una materia con cada requisito.

    + +

    Cláusulas

    + +

    Cada una de las sentencias = unidades de información de una base de conocimiento. Las cláusulas deben terminar con un punto . El ejemplo tiene 15 cláusulas. Cada cláusula participa en la definición de un predicado, define ciertos casos para los que un predicado se verifica. En el ejemplo:

    + +
      +
    • las cláusulas 1 a 4 definen por extensión el predicado hombre/1.
    • +
    • la cláusula 5 define el predicado mortal/1, indicando que cualquier individuo que sea hombre, es mortal.
    • +
    • las cláusulas 6 y 7 definen por extensión el predicado ciudad/1
    • +
    • etc..
    • +
    + +

    Cada cláusula puede ser un hecho o una regla.

    + +

    Un hecho hace una afirmación incondicional (no depende de ninguna condición para ser cierta), generalmente sobre un individuo particular.

    + +

    En el ejemplo todas las cláusulas son hechos salvo las que definen los predicados mortal/1 y sonConciudadanos/2. Sintácticamente, los hechos son las claúsulas que no incluyen el símbolo :- .

    + +

    Una regla define una implicación, es decir que define que si se cumplen ciertas condiciones, entonces un predicado se verifica para ciertos individuos.

    + +

    La cláusula mortal(X):- hombre(X). sirve para determinar de forma general (por comprensión, no por extensión) si un cierto X es mortal. Esta definición indica que si se cumple la condición hombre(X) entonces el predicado mortal/1 se cumple para ese mismo X. Una regla se compone de una cabeza (mortal(X)) y un cuerpo (en este caso es solamente hombre(X)), unidos por el símbolo :- que denominamos cuello. Si vemos una regla como una implicación con antecedente y consecuente, está invertida respecto a lo que se vio al estudiar lógica: la cabeza es el consecuente, el cuerpo es el antecedente.

    + +

    El predicado sonConciudadanos/2 también se define con una regla, sólo que un poco más compleja porque depende de una conjunción entre dos condiciones más sencillas.

    + +

    Consultas

    + +

    Son la forma de usar un programa en lógico, se hace una consulta, y se obtiene una o varias respuestas.

    + +

    Existen dos tipos de consulta:

    + + + + + + + + + + + + +

    Individuales

    se hacen sobre individuos específicos. Por ejemplo:

    +

     ?- mortal(socrates).
    + ?- sonConciudadanos(socrates,solon).

    Existenciales

    Se verifica si existe algún individuo que satisfaga la consulta. Además, Prolog a veces nos sabe dar "ejemplos" de individuos que hacen verdadera la consulta. Por ejemplo:

    +

     ?- mortal(X).
    + ?- sonConciudadanos(X,Y).
    + ?- sonConciudadanos(solon,Y).

    +

    En el segundo caso cada respuesta es un par de conciudadanos (o sea, de individuos relacionados por el predicado sonConciudadanos/2, mientras que en el tercero cada respuesta es un conciudadano de Solón.
    +En este tipo de consultas aparecen variables o incógnitas. Por ese motivo este tipo de consultas también son llamadas consultas variables.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigma-logico.html b/wiki/articles/paradigma-logico.html new file mode 100644 index 0000000000..60e92b6256 --- /dev/null +++ b/wiki/articles/paradigma-logico.html @@ -0,0 +1,419 @@ + + + + + + + + + + + Paradigma logico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigma logico +

    +
    + + + +
    +

    Este paradigma se basa en los conceptos de lógica matemática, se basa predicados que caracterizan o relacionan a los individuos involucrados y la deducción de las posibles respuestas a una determinada consulta.

    + +

    Es un paradigma declarativo. No hay asignaciones destructivas, se trabaja con el concepto de unificación.

    + +

    Las bases del paradigma

    + + + +

    Modelando la información

    + + + +

    Algunas Características Relevantes

    + + + +

    Predicados de Orden Superior

    + + + +

    Errores y preguntas frecuentes

    + + + +

    Más características

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/paradigmas-de-programacion.html b/wiki/articles/paradigmas-de-programacion.html new file mode 100644 index 0000000000..157a11d71c --- /dev/null +++ b/wiki/articles/paradigmas-de-programacion.html @@ -0,0 +1,400 @@ + + + + + + + + + + + Paradigmas de programacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Paradigmas de programacion +

    +
    + + + +
    + + +

    Los paradigmas

    + + + +

    Conceptos Transversales

    + + + +

    Y algunas discusiones interesantes que surgieron alrededor de estas ideas:

    + + +

    Material de lectura extra

    + +

    Concepts, Techniques and Models of Computer Programming

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/parsers-monadicos.html b/wiki/articles/parsers-monadicos.html new file mode 100644 index 0000000000..c24435b8dc --- /dev/null +++ b/wiki/articles/parsers-monadicos.html @@ -0,0 +1,319 @@ + + + + + + + + + + + Parsers monadicos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Parsers monadicos +

    +
    + + + +
    +

    Este artículo está en construcción.

    + +

    Un uso muy simpático para el concepto de mónadas es la posibilidad de construir parsers a partir de ellas. Esto es posible en diferentes lenguajes, como Haskell y Scala. Este artículo intenta compendiar algo de información al respecto.

    + +

    Parsers Monádicos en Scala

    + +

    Algunos artículos interesantes:

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/patrones-de-comunicacion-entre-componentes.html b/wiki/articles/patrones-de-comunicacion-entre-componentes.html new file mode 100644 index 0000000000..97d6d09117 --- /dev/null +++ b/wiki/articles/patrones-de-comunicacion-entre-componentes.html @@ -0,0 +1,612 @@ + + + + + + + + + + + Patrones de comunicacion entre componentes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Patrones de comunicacion entre componentes +

    +
    + + + +
    +

    AVISO @Deprecated

    + +

    Este contenido está desactualizado, se reemplaza por el apunte que aparece en https://docs.google.com/document/d/1EVPwqFyq2TW5Z5_VUeWdh9yLesxPBbSBzke2jHNURuk/edit?usp=sharing

    + +

    Memoria compartida (shared memory)

    + +

    La memoria compartida es un espacio común de datos en el que múltiples componentes (por ejemplo: procedimientos) pueden leer y escribir información. Implementaciones típicas de memoria compartida son las variables globales o las bases de datos como herramienta de integración entre componentes.

    + +

    Ejemplo

    + +

    A continuación podemos ver un ejemplo de una pila programada en C utilizando esta forma de compartir información:

    + +

     #include <stdio.h> + #define SIZE 50 +  + int  current, stack[SIZE]; +  + void init() { +   current = 0; /* initialize current */ + } +  + void push(int i) { +   current++; +   if(current == (SIZE)) { +     printf("Stack Overflow.\n"); +     exit(1); +   } +   stack[current] = i; + } +  + int pop(void) { +   if(current == 0) { +     printf("Stack Underflow.\n"); +     exit(1); +   } +   current--; +   return stack[current+1]; + } +  + int main(void) { +   int value; +   init(); +    +   push(1); +   push(2); +   printf("First value on top is %d\n", pop()); +   printf("Second value on top is %d\n", pop()); +   printf("Third value on top is %d\n", pop()); +   printf("end\n"); +        +   return 0; + }

    + +

    Consecuencias

    + +

    Algunas consecuencias de esta forma de compartir información son:

    + +
      +
    • No hay un mecanismo sencillo para saber qué procedimientos incluyen referencias a las variables globales y
    • +
    • No es posible tener dos pilas simultáneamente, en caso de intentarlo se mezclaría la información de ambas.
    • +
    • La modificación de cualquiera de las operaciones que acceden a la estructura de datos implica revisar su buen comportamiento en relación con todas las demás (que, como se dijo antes, puede no ser posible saber exactamente cuáles son). Lo mismo ocurre si se desea modificar la estructura de los datos compartidos.
    • +
    + +

    En el caso general la memoria compartida representa un grado alto de acoplamiento ya que a priori no es posible saber qué componentes modifican o leen qué parte de los datos. En sistemas donde la información compartida está sostenida en un motor de bases de datos (por ejemplo RDBMS), estos pueden mitigar parcialmente este problema al implementar esquemas de seguridad que restrinjan en parte el acceso a los datos a sólo la parte necesaria de cada componente.

    + +

    Por otro lado, existen tecnologías que permiten definir variables con alcance o ‘‘scopes’’ más limitado que global, reduciendo de esta manera el acoplamiento únicamente a los componentes que tienen acceso al scope específico. Un caso particular de scope son las variables de instancia de un objeto, como se muestra en el ejemplo siguiente.

    + +

    Ejemplo: Java

    + +

     public class Stack { +   public static final SIZE = 50; +   private int  current; +   private int[] stack =; +    +   public Stack () { +     current = 0; +     stack = new int[50]; +   } +    +   public void push(int i) { +     current++; +     if(current == (SIZE)) { +       System.out.println("Stack Overflow.\n"); +       System.exit(1); +     } +     stack[current] = i; +   } +    +   public int pop() { +     if(current == 0) { +       System.out.println("Stack Underflow.\n"); +       System.exit(1); +     } +     current--; +     return stack[current+1]; +   } +    +   public static void main() { +     Stack s = new Stack(); +      +     s.push(1); +     s.push(2); +     System.out.println("First value on top is %d\n", s.pop()); +     System.out.println("Second value on top is %d\n", s.pop()); +     System.out.println("Third value on top is %d\n", s.pop()); +     System.out.println("end\n"); +        +     return 0; +   } + }

    + +

    Call & Return

    + +

    En el mecanismo de call & return la comunicación se da entre un componente invocante o llamador (caller) que invoca o referencia a otro componente invocado o llamado (callee). Si bien el flujo de información es bidireccional, es asimétrico:

    + +
      +
    • El componente invocado puede recibir parámetros, que le permiten al invocante transferirle información mediante argumentos.
    • +
    • En el caso general el componente invocado puede producir un valor de retorno, mediante este mecanismo se logra la bidireccionalidad de la comunicación. En algunas tecnologías pueden existir limitaciones que restringen el uso de valores de retorno, en ese caso la comunicación será unidireccional.
    • +
    + +

    Ejemplo puro

    + +

    El ejemplo más preciso de esta idea se encuentra en los lenguajes funcionales puros, es decir, sin la posibilidad de efecto. La ausencia de efecto obliga a que toda la comunicación sea por medio de los parámetros.

    + +

     type Stack = [Int] +  + empty :: Stack + empty = [] +  + push :: Int -> Stack -> Stack + push i s = i : s +  + pop :: Stack -> (Int, Stack) + pop [] = error "Stack Underflow.\n" + pop (i:s) = (i, s) +  + discard = snd . pop + peek = fst . pop +  + test1 = peek $ discard $ push 2 $ push 1 $ empty + 

    + +

    Consecuencias

    + +

    Si bien la comunicación puede ser bidireccional, el conocimiento (y por lo tanto el acoplamiento) es a priori unidireccional, es decir, el componente llamado no tiene ningún conocimiento de el origen del mensaje y aún puede devolver información sin tener conocimiento del destino de la misma.

    + +

    La aclaración a priori en el párrafo anterior se explica porque en lenguajes con efecto (es decir, la mayoría de los lenguajes que usamos habitualmente en la industria) los parámetros podrían ser modificados dentro del componente. Para estudiar el acoplamiento en estos contextos debemos determinar cuánto debe saber el componente llamado acerca de sus parámetros, por ejemplo si puede o no modificarlos. Esto a su vez depende del tipo de pasaje de parámetros que utilicemos (por ejemplo, pasaje de parámetros por copia o pasaje de parámetros por referencia). En el caso de pasaje por parámetros por referencia, la modificación del parámetro recibido puede ser un mecanismo adicional de comunicación entre los componentes.

    + +

    TODO: Este ejemplo no inicializa correctamente la pila y tira error.

    + +

    Ejemplo con Call-By-Reference

    + +

     #include <stdio.h> + #include <stdlib.h> + #define SIZE 50 +  + typedef struct stack { +   int  current, stack[SIZE]; + } stack; +  + stack* empty() { +   stack* s = (stack*) malloc(sizeof(stack)); +   return s; + } +    + void push(stack* s, int i) { +   s->current++; +   if(s->current == SIZE) { +     printf("Stack Overflow.\n"); +     exit(1); +   } +   s->stack[s->current] = i; + } +  + int pop(stack* s) { +   if(s->current == 0) { +     printf("Stack Underflow.\n"); +     exit(1); +   } +   return s->stack[s->current--]; + } +    + int main(void) { +   stack* s = empty(); +    +   push(s, 1); +   push(s, 2); +   printf("First value on top is %d\n", pop(s)); +   printf("Second value on top is %d\n", pop(s)); +   printf("Third value on top is %d\n", pop(s)); +   printf("end\n"); +        +   return 0; + }

    + +

    Excepciones

    + +

    Continuations

    + +

     class MyCPSStack { +    def elements = [] +  +    static empty(yield) { +     yield(new MyCPSStack()) +    } +       +    void push(element, yield) { +      yield(new MyCPSStack(elements: [element] + elements)) +    } +       +    void pop(yield) { +      if(elements.empty) +        throw new Exception("Stack Underflow") +      yield([elements.head(), new MyCPSStack(elements: elements.tail())]) +    } +  +    def discard(yield) { +       pop({ yield(it[1]) })   +    } +  +     //it significa "el (único) argumento que recibe este bloque de código" +     def peek(yield) { +       pop({ yield(it[0]) })   +     } +  +    String toString() { +     return elements.toString() +    } +  }  +  +  + MyCPSStack.empty({  it.push(1, {  it.push(2, {  it.discard({  it.peek({  print it })  })  }) }) })

    + +

    http://en.wikipedia.org/wiki/Continuation-passing_style http://en.wikipedia.org/wiki/Callback_(computer_science)

    + +

    Eventos

    + +

    Mensajes asincrónicos

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/pattern-matching--polimorfismo-y-diseno.html b/wiki/articles/pattern-matching--polimorfismo-y-diseno.html new file mode 100644 index 0000000000..f229557c88 --- /dev/null +++ b/wiki/articles/pattern-matching--polimorfismo-y-diseno.html @@ -0,0 +1,313 @@ + + + + + + + + + + + Pattern matching polimorfismo y diseno + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Pattern matching polimorfismo y diseno +

    +
    + + + +
    +
      +
    • Incorporar declaraciones de operaciones vs incorporar definiciones de operaciones
    • +
    • pattern matching no es tan solo un switch
    • +
    • jerarquias acotadas vs jerarquias abiertas
    • +
    • ejemplos en scala
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/pattern-matching-en-haskell.html b/wiki/articles/pattern-matching-en-haskell.html new file mode 100644 index 0000000000..a6fa74ed32 --- /dev/null +++ b/wiki/articles/pattern-matching-en-haskell.html @@ -0,0 +1,508 @@ + + + + + + + + + + + Pattern matching en haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Pattern matching en haskell +

    +
    + + + +
    +

    Pattern Matching es el concepto asociado al chequeo estructural de un dato respecto de una estructura esperada. El uso de pattern matching tiene la ventaja de simplificar mucho la codificación, ya que sólo escribimos la forma de lo que esperamos y podemos desglosar los componentes de estructuras complejas.

    + +

    Una desventaja asociada a usar pattern matching en vez de funciones para acceder a los elementos de las tuplas es que nuestro código se verá muy afectado ante un cambio en las estructuras manejadas. El simple hecho de agregar un elemento más a la tupla que representa a nuestro elemento de dominio provocará un cambio en el tipo del mismo y el mismo se propagará en todos los lugares donde se haya utilizado esta estructura directamente.

    + +

    Ejemplos de matcheo

    + +

    Con números y strings

    + +

    Si queremos saber si el nombre de un día de la semana es fin de semana podemos hacer:

    + +
    esFinDeSemana dia = dia == "Sábado" || dia == "Domingo"
    +
    + +

    Sin embargo esta otra definición también es válida:

    + +
    esFinDeSemana' "Sábado" = True
    +esFinDeSemana' "Domingo" = True
    +esFinDeSemana' _ = False
    +
    + +

    La última definición es necesaria, ya que a diferencia del paradigma lógico, no contamos con el principio de universo cerrado y si sólo definimos esFinDeSemana’ para “Sábado” y “Domingo” y consultamos por otro día, Haskell nos mostrará un error porque el patrón no calza con ningún elemento del dominio esperado. Para que esta función funcione correctamente es importante que el encabezado con la variable anónima, que matchea con cualquier patrón, sea la última definición de esFinDeSemana’, de lo contrario no habrá ningún elemento del dominio cuya imagen pueda ser True (por unicidad).

    + +

    Acá tenemos un ejemplito recursivo típico para pattern matching con números:

    + +
    factorial 0 = 1 
    +factorial n = n * factorial (n - 1)
    +
    + +

    Para evitar loops infinitos, es importante poner el caso base primero para que matchee con el 0, ya que la variable n también matchearía con este valor.

    + +

    Con tuplas

    + +

    Si tengo los valores

    + +
    v1 = (2,5)
    +v2 = (3,5)
    +v3 = (8,5)
    +
    + +

    El patrón (x,5) matchea con los tres valores.

    + +

    También el patrón (x,y) matchea con los tres valores.

    + +

    También el patrón (_,5) matchea con los tres valores.

    + +

    También el patrón (_,_) matchea con los tres valores.

    + +

    También el patrón unaTupla matchea con los tres valores.

    + +

    Con listas

    + +

    Ahora, si tengo una lista

    + +
    lista1 = [(2,5),(5,3),(3,3)]
    +lista2 = [(2,5)]
    +
    + +

    El patrón (x,5) no matchea con lista1 ni con lista2. ¡Es una tupla, no una lista! Antes de tratar de matchear, Haskell nos va a tirar un error de tipos.

    + +

    El patrón (x:xs) matchea con lista1, siendo x = (2,5) y xs = [(5,3),(3,3)] y matchea con lista2, siendo x = (2,5) y xs = []

    + +

    El patrón [x] no matchea con lista1 porque tiene más de un elemento, pero sí matchea con lista2, siendo x = (2,5)

    + +

    El patrón (x:_) matchea con lista1, siendo x = (2,5) y matchea con lista2, siendo x = (2,5)

    + +

    El patrón (x:y:_) matchea con lista1, siendo x = (2,5) e y = (5,3), y no matchea con lista2 porque sólo tiene un elemento

    + +

    El patrón unaTupla matchea con lista1 siendo unaTupla = [(2,5),(5,3),(3,3)] y matchea con lista2 siendo unaTupla = [(2,5)]. Es sólo un nombre de variable, con lo cual no restringe realmente el tipo del valor para que sea una tupla.

    + +

    Con data

    + +

    (En algunos cursos no se da data, para más información ver acá: Data: Definiendo nuestros tipos en Haskell) Suponiendo que tenés

    + +
    data Coordenada = Coord Int Int
    +
    + +

    (el tipo es Coordenada y el constructor es Coord)

    + +

    Donde se puede aplicar la misma idea

    + +
    lista1 = [Coord 2 5,Coord 5 3,Coord 3 3]
    +lista2 = [Coord 2 5]
    +
    + +

    El patrón (Coord x 5) no matchea con lista1 ni con lista2. ¡Es una Coordenada, no una lista! Antes de tratar de matchear, Haskell nos va a tirar un error de tipo.

    + +

    El patrón (Coord x y:restoCoords) matchea con lista1, siendo x = 2, y = 5 y restoCoords = [Coord 5 3,Coord 3 3] y matchea con lista2, siendo x = 2, y = 5 y restoCoords = []

    + +

    El patrón [x] no matchea con lista1 pero si matchea con lista2, siendo x = Coord 2 5

    + +

    El patrón (x:_) matchea con lista1 y matchea con lista2 siendo x = Coord 2 5

    + +

    El patrón (x:y:_) matchea con lista1 siendo x = Coord 2 5 y y = Coord 5 3 pero no matchea con lista2

    + +

    El patrón unaTupla matchea con lista1 y matchea con lista2 porque no es más que una variable sin ninguna restricción después de todo

    + +

    Patrones con sinónimos (at Pattern)

    + +

    Usamos este patrón para definir un sinónimo, o sea necesito por un lado el patrón para tomar algunos de sus componentes y por otro todo junto para la hacer otra cosa, pongamos un par de ejemplos:

    + +
    ordenada [_] = True
    +ordenada (x1:x2:xs) = x1 > x2 && ordenada x2:xs
    +
    + +

    Puede mejorarse sutilmente con un sinónimo.

    + +
    ordenada [_] = True
    +ordenada (x1:xs@(x2:_)) = x1 > x2 && ordenada xs
    +
    + +

    Otro ejemplo, entre dos complejos representados con tuplas, obtener el que tiene mayor parte real:

    + +
    mayorParteReal (a@(a1, _)) (b@(b1, _))
    + | a1 > b1 = a`
    + | otherwise = b
    +
    + +

    Y otro con listas por comprensión:

    + +
    promedioDeAprobados alumnos = promedio [ promedio notas | alumno@(_,notas) <- alumnos, aprobo alumno ]
    +
    + +

    Sobre la Variable Anónima

    + +

    La variable anónima _ (guión bajo) funciona, en términos de matcheo, como una variable común:

    + +
    esCero 0 = True
    +esCero x = False
    +
    + +

    Es lo mismo que decir:

    + +
    esCero 0 = True
    +esCero _ = False
    +
    + +

    De hecho, esta última opción es mejor, porque ayuda a la expresividad: si la variable no se usa en la devolución (a la derecha del igual, ó a la derecha de la guarda) entonces mejor ni ponerle nombre. Por ejemplo:

    + +
    anioActual = 2014
    +edad (nombre, anioNac, cantPerros) = anioActual - anioNac
    +
    + +

    En ese caso la función edad recibe una tupla pero a la derecha, en la definición de la función, no hace faltan el nombre y el cantPerros. Entonces, usamos variables anónimas:

    + +
    edad ( _, anioNac, _) = anioActual - anioNac
    +
    + +

    Error común con Variables Anónimas

    + +

    Muchas veces pensamos que no necesitamos una variable, cuando en realidad sí la usamos a la derecha del igual. Por ejemplo, si queremos tomar esa definición de “persona” como una tupla de tres, y agregarle perros a la persona, debemos devolver a una persona, pero cambiando sólo la cantidad de perros.

    + +

    Esto es erróneo:

    + +
    agregarPerros cant (_, _, cantPerros) = (_, _, cantPerros + cant)
    +
    + +

    ¡Son variables anónimas! Si quiero usarlas a la derecha del igual (ó sea, si quiero que sean parte de lo que devuelvo) entonces tengo que usar variables comunes.

    + +

    Esto está bien:

    + +
    agregarPerros cant (nombre, anioNac, cantPerros) = (nombre, anioNac, cantPerros + 1)
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/pepita.html b/wiki/articles/pepita.html new file mode 100644 index 0000000000..4e83bc712e --- /dev/null +++ b/wiki/articles/pepita.html @@ -0,0 +1,382 @@ + + + + + + + + + + + Pepita + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Pepita +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Pepita

    + +

    En muchos ejemplos en esta Wiki surge la figura de Pepita, la golondrina. Pero ¿quién es Pepita, de dónde viene y para qué está acá?

    + +

    Características Básicas

    + +

    Pepita es una golondrina, que tiene un cierto nivel (medido en Joules) variable de energía, y sabe hacer al menos dos cosas: volar y comer, aunque a veces y según el ejercicio se le agregan comportamientos extra: volar hacia ciertos lugares, llevar paquetes, etc.

    + +

    Volar

    + +

    Cuando vuela, consume una cierta cantidad arbitraria de energía. En ocasiones este mensaje está parametrizado según la cantidad de kilómetros que vuela; en ese caso la pérdida de energia es una función lineal de esta distancia. Por ejemplo: “pepita consume un joule para cada kilómetro que vuela, más 10 joules de “costo fijo” en cada vuelo”

    + +

    Comer

    + +

    Pepita come alpiste, y cuando lo hace, su energía se incrementa linealmente en función de la cantidad de gramos de alpiste consumidos. Por ejemplo: “cuando come, adquiere 4 joules por cada gramo que come”

    + +

    Historia

    + +

    Pepita fue creada por Carlos Lombardi hacia 2004, y terminó de cobrar forma con los aportes de Germán Leiva y Nico Passerini.

    + +

    Links Externos

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/pharo-para-programadores-ozonosos.html b/wiki/articles/pharo-para-programadores-ozonosos.html new file mode 100644 index 0000000000..029f42b3f3 --- /dev/null +++ b/wiki/articles/pharo-para-programadores-ozonosos.html @@ -0,0 +1,586 @@ + + + + + + + + + + + Pharo para programadores ozonosos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Pharo para programadores ozonosos +

    +
    + + + +
    +

    La migración desde trabajar con Ozono a pasar a la versión full de Pharo puede ser complicado en ciertos sentidos pero más o menos es lo mismo pero tenemos que tener en cuenta las diferencias.

    + +

    Clases vs. Objetos

    + +

    La primer diferencia que tenemos en este nuevo ambiente es que Pharo esta centrado en las clases y no en los objetos.

    + +

    Como ya vimos en las clases teóricas, los objetos ya no los vamos a crear uno por uno sino que vamos a crear los objetos a partir de clases.

    + +

    Por lo tanto, la forma que tiene Pharo (y muchos otros lenguajes orientados a objetos) es organizarse alrededor clases.

    + +

    System Browser, el centro de nuestro desarrollo

    + +

    Para comenzar vamos a necesitar una imagen de Pharo, cualquier imagen nos va a servir; pueden seguir usando la que tiene instalada Ozono :D.

    + +

    Nuestro principal amigo en el desarrollo con Pharo va a ser el System Browser. Este lo encontramos dentro del menú principal de Pharo.

    + +

    + +

    Esto nos va a abrir la siguiente ventana (es bastante compleja para decirle ventanita).

    + +

    + +

    Secciones del System Browser

    + +

    Esta ventana se divide en distintas secciones, esta ventana es central, presenta mucha mucha mucha información por eso vamos a analizarla por secciones.

    + +

    + +

    Estas Secciones son:

    + +
      +
    • Categorias de clases: en esta sección aparece una forma de categorizar las clases. Las categorías de las clases en Pharo
    • +
    + +

    se llaman Packages, estos paquetes de clases pueden contener una o más subcategorías dentro.

    + +
      +
    • Clases: una vez que selecciono un paquete se me van a mostrar las clases que están definidas en ese paquete. Porque algunas
    • +
    + +

    aparecen con signo de admiración (!), porque no tienen escrita la documentación que explica que hace la clase.

    + +
      +
    • Categorías de Métodos: cuando selecciono una clase se me van a mostrar los métodos que tiene definida esa clase. Estos
    • +
    + +

    métodos pueden estar clasificados en distintas categorías, esto es muy útil como forma de documentación y suma mucho valor cuando comienza a crecer mi programa.

    + +
      +
    • Metodos: al ir navegando las categorías de los métodos van a ir mostrándome la lista de métodos de esa clase en la categoría
    • +
    + +

    seleccionada.

    + +
      +
    • Área de Edición de Código: En esta área de la ventana es donde se realiza la edición del código. Si elegimos un método vamos a
    • +
    + +

    ver el código de ese método, pero si elegimos una clase nos muestra un código raro. No entremos en pánico, ese código es la definición de la clase, ya vamos a entrar en el detalle de como hacerlo.

    + +

    Por ahora debemos entender las distintas secciones del System Browser pronto vamos a ver para que se usa cada cosa con un ejemplo.

    + +

    Workspaces

    + +

    Bueno, bueno, todo muy bonito pero a mi me gustaba enviar mensajes a mis objetos. Esto lo perdimos, esto es una mierda. No, no perdimos nada!!!

    + +

    La forma de enviar mensajes y probar nuestro programa van a ser nuestros bonitos workspace (después vamos a hablar de tests, pero eso es otra versión mucho más cheta aunque menos interactiva).

    + +

    + +

    Para crear un workspace lo hacemos desde el menú principal de Pharo, es el mismo que usamos inicialmente.

    + +

    Además podemos tener muchos workspace abiertos.

    + +

    Los workspace de Pharo se usan de la misma manera que los de Ozono que ya usamos previamente. Pero con una variación interesante, podemos definir variables dentro del workspace. Estas variables son locales al workspace. Para definirlas debemos usarlas directamente, asignandole un valor. Cuando evaluemos esa línea va a crearse la variable.

    + +

    Atención, los workspace no se van a guardar solitos como en Ozono, tenemos que guardarlos a mano. Normalmmente no nos vamos a preocupar por esto ya que el código que pongamos en el workspace es para pruebas rápidas. Si queremos guardar algo que vamos a probar varias veces nos sirve la idea de Tests, ya la vamos a ver; pero por ahora con el workspace nos sirve.

    + +

    Los workspace se guardan como archivos de texto con extensión .ws, para poder guardar y cargar estos archivos tenemos que usar la flechita que esta a la derecha y arriba del workspace.

    + +

    + +

    Un ejemplo Paso a Paso

    + +

    Para poder mostrar como se usa Pharo, vamos a implementar el siguiente ejemplo.

    + +

    Vamos a tener que construir un sistema para administrar camiones en una empresa de logística. De cada camión vamos a saber su capacidad en kilos y su carga actual, y además podemos saber si el camión esta lleno o no.

    + +

    Al analizar y plantear una solución al problema, identificamos que todos los objetos camiones tienen el mismo comportamiento; por lo que extrajimos la siguiente clase:

    + +

    + +

    Tenemos que recordar que la solución se da con los objetos que representan los camiones, las clases sirven para crear muchos camiones iguales, o sea se comportan todos juntos.

    + +

    Recordemos un poquito la forma de comunicación con los diagramas de clase. Este rectángulo que representa la clase tiene 3 secciones. En la superior va el nombre de la clase. En la del medio los distintos atributos que tienen los objetos creados con esta clase. Y en la inferior los mensajes que entienden los objetos creados con la clase.

    + +

    Perfecto ya sabemos que es lo que tenemos que hacer, ahora vamos a implementarlo en Pharo!

    + +

    Creación de Paquetes

    + +

    Para comenzar tenemos que crear un paquete nuevo dentro de Pharo. Todas las clases de Pharo estan definidas dentro de un paquete, es muy recomendable que creemos un paquete para cada uno de los ejercicios o problemas o sistemas que creemos.

    + +

    Para crear un paquete tenemos que hacer click derecho sobre el sector de paquetes del System Browser y elegir la opción Add Package…. Esta opción nos va a preguntar el nombre del nuevo Paquete.

    + +

    Podemos ponerle el nombre que queramos, pero existe una convención que se usa en todos lados y que Pharo va a usar para presentarnos la información. Esta convención es separar las palabras con guión del medio.

    + +

    En este caso vamos a crear el paquete Logistica.

    + +

    Una aclaración importante, es que aunque es probable que Pharo se banque nombres con acentos o ñ o cualquier caracter UTF-8, a los programadores nos gusta obviar los acentos y las ñ; porque siempre siempre siempre van a traer problemas.

    + +

    Cuando creamos el paquete nos debería quedar algo así:

    + +

    + +

    Creación de Clases

    + +

    Ya tenemos nuestro paquete creado, por ahora esta vació y triste y solo; por lo que vamos a comenzar creando la clase Camión.

    + +

    Para crear una clase tenemos que hacer las siguientes operaciones:

    + +
      +
    1. Hacer click sobre el paquete donde va a vivir nuestra nueva clase.
    2. +
    3. Ingresar la definición de la clase en el Área de Edición de Código, ahora vamos a hablar de que hay que escribir ahí.
    4. +
    5. Aceptar la definición, ya sea haciendo Ctrl+S o haciendo botón derecho y darle la opción Accept.
    6. +
    + +

    Definición de una Clase

    + +

    Las clases en cualquier ambiente de Smalltalk se definen a partir de un envió de mensaje. Nadie en la vida se acuerda este mensaje que hay que mandar a la clase Object, pero al hacer click sobre un paquete la herramienta ya nos propone un template:

    + +
      Object subclass: #NameOfSubclass
    +         instanceVariableNames: ''
    +         classVariableNames: ''
    +         category: 'Logistica'
    +
    + +

    La definición de nuestra clase Camion es la siguiente:

    + +
      Object subclass: #LgCamion
    +         instanceVariableNames: 'capacidad carga'
    +         classVariableNames: ''
    +         category: 'Logistica'
    +
    + +

    Si se fijan no es tan tan loca.

    + +

    Las cosas que voy a modificar son:

    + +
      +
    • El nombre de la clase, es eso que esta después del numeral
    • +
    • Las variables de instancia, acá agrego dentro del string cada uno de los nombres de las variables de instancia separados por un espacio.
    • +
    + +

    En este caso tengo dos variables de instancia, capacidad y carga.

    + +
      +
    • Nombre de la categoría donde esta clase, acá ya me pone la que corresponde al paquete donde estoy parado, pero siempre lo puedo cambiar.
    • +
    + +

    Un minuto cerebrito, acá dijimos que ibamos a crear la clase Camion y vos le pusiste LgCamion; me estas cargando o todas las clases comienzan con Lg???

    + +

    Ninguna de las dos cosas, es un prefijo que identifica a nuestro paquete; como cree un paquete llamado Logistica definí que el prefijo que identifique a las clases dentro de este con el prefijo Lg.

    + +

    Esto lo tenemos que hacer porque Pharo no tiene espacios de nombres independientes, o sea no puedo tener dos clases con el mismo nombre, si quisiera crear una clase con el mismo nombre de otra que existe, voy a pisar la original. Por eso vamos a generar nombres únicos teniendo un prefijo para el paquete y el nombre de la clase.

    + +

    Si estamos muy muy muy seguros que no existe otra clase que se llame Camion, podría ponerle ese nombre. Pero yo debo contarle el estandard.

    + +

    Después de crear la clase nos debería quedar algo así:

    + +

    + +

    Atención, no nos preocupemos por ese signo de admiración rojo. Ya lo dijimos, pero lo recuerdo, es un indicativo que la clase no esta documentada. Nada importante, por ahora, es algo que nos debería importar.

    + +

    Definición de Métodos

    + +

    Ya definimos nuestra clase ahora debemos agregarle métodos.

    + +

    Para poder agregar un método a una clase, tenemos que tener seleccionada la clase donde lo vamos a definir y hacer click sobre la categoría del método que vamos a generar; si no tenemos la categoría, la podemos crear o hacer click en no messages que es la que tengo cuando esta vacía o en – all – si ya tiene alguna.

    + +

    Cuando hacemos esto la sección de edición de código nos va a ofrecer el template, esto no es solo necesario para que nos muestre el template, sino que lo tengo que hacer para que Pharo sepa donde voy a meter el método.

    + +

    + +

    Entonces vamos a escribir el código de nuestro primer método, lo que vamos a hacer es un mensaje para que el camión nos devuelva su capacidad:

    + +
          capacidad
    +          ^ capacidad
    +
    + +

    Para guardar el método creado, tenemos que hacer CTRL+s o botón derecho y elegir la opción Accept.

    + +

    Cuando hacemos esto, nos queda el siguiente resultado.

    + +

    + +

    Probando nuestros Objetos

    + +

    Ya tenemos creada nuestra clase, ahora probemos los objetos que creamos. Para poder crear objetos y mandarles mensajes necesitamos usar un workspace.

    + +

    En un nuevo workspace vamos a escribir el siguiente código.

    + +
          unCamion := LgCamion new.
    +      unCamion capacidad.
    +
    + +

    Podemos ir ejecutando línea a línea. La primera nos conviene ejecutarla con un Do-It (o haciendo Ctrl+d), ya que es una línea que tiene efecto de lado. Esta línea crea un nuevo objeto a partir de la clase LgCamion y lo asigna a la variable local unCamion.

    + +

    La 2da línea la vamos a ejecutar con un Print-It (o haciendo Ctrl+p), ya que es una expresión que va a devolver la capacidad del camión.

    + +

    Dando como resultado lo siguiente:

    + +

    + +

    Pero porque cuando evaluamos la 2da expresión nos devuelve nil? Bueno, porque todas los atributos de un objeto arrancan en nil.

    + +

    Por eso debemos agregarle el método para poder establecer los valores de los objetos. Vamos a agregar los siguientes métodos a la clase LgCamion:

    + +
         capacidad: unValor.
    +       capacidad := unValor.
    +
    + +
         carga
    +       ^ carga.
    +
    + +
         carga: unValor
    +       carga:=unValor.
    +
    + +

    Además vamos a definir el método para responder al mensaje estasLleno.

    + +
         estasLleno.
    +       ^ capacidad = carga.
    +
    + +

    Entonces una vez que tenemos este mensaje podemos hacer una prueba más interesante con el siguiente workspace.

    + +
         unCamion := LgCamion new.
    +     unCamion capacidad:1000. 
    +     unCamion carga:1000.
    +     unCamion estasLleno.
    +
    + +

    Este workspace ya nos permite probar una variante, que podemos ir modificando para probar nuestros objetos. Una alternativa interesante para esto, es poder crear tests unitarios.

    + +

    Como guardar mis programas

    + +

    En Pharo, los programas se guardan dentro de la imagen, o sea tengo que ir guardando la imagen con el código y los objetos de mis programas.

    + +

    Exportar a un .st

    + +

    Además puedo exportar los paquetes como un archivo .st. Para realizar esto podemos hacerlo desde el System Browser y con el botón derecho sobre un paquete y eligen la opción File Out.

    + +

    Al hacer esto se genera un archivo con el nombre del paquete y la extensión .st que incluye todo el código fuente de las clases del paquete.

    + +

    Importar un .st

    + +

    Para poder importar un archivo .st lo más fácil es arrastrar el archivo sobre una imagen de Pharo que se encuentre corriendo y al soltarlo elegir la opción FileIn Entire File y listo ya lo va a cargar en la imagen.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/phm-script-mapeo-manual-or.html b/wiki/articles/phm-script-mapeo-manual-or.html new file mode 100644 index 0000000000..270d39cf4b --- /dev/null +++ b/wiki/articles/phm-script-mapeo-manual-or.html @@ -0,0 +1,358 @@ + + + + + + + + + + + Script mapeo manual Objetos / Relacional + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Script mapeo manual Objetos / Relacional +

    +
    + + + +
    +
      +
    • Presentación del ejercicio de los partidos de fútbol +
        +
      • modelo de objetos
      • +
      • traslación al modelo relacional
      • +
      +
    • +
    • Creamos las tablas (DDL: Data Definition Language)
    • +
    • Insertamos valores desde el modelo relacional (mediante scripts de manipulación de datos o DML) +
        +
      • ¿O -> R o R -> O?
      • +
      • Crear Juego de datos en alguna de las dos tecnologías
      • +
      +
    • +
    • Intro a JDBC. Driver o controlador como el componente que permite a nuestra aplicación (en este caso JDK) interactuar con un motor de base de datos. +
        +
      • Conexión +
          +
        • Externalización a un archivo / Encriptación
        • +
        • Pool de conexiones
        • +
        +
      • +
      • Statement +
          +
        • Statement de consulta que devuelve Resultsets
        • +
        • Statement de inserción, eliminación o actualización que sólo implica ejecución
        • +
        +
      • +
      • Prepared Statement
      • +
      +
    • +
    • Mapeo manual +
        +
      • Diseñar objetos que modelen sólo la estructura (ej: EJB 2.x) vs. usar los objetos de dominio +
          +
        • No hay razón para mantener una doble jerarquía de objetos sin comportamiento
        • +
        +
      • +
      • Hidratación del grafo de objetos, se segmenta por caso de uso +
          +
        • cuando quiero saber quién ganó, no necesito saber los que jugaron, sólo el resultado
        • +
        • cuando quiero saber si un jugador estuvo en un partido, tengo que bajar el grafo de objetos de Equipo, Resultado, Formación hasta los jugadores relacionados con la formación
        • +
        +
      • +
      • Ventajas +
          +
        • mayor control sobre el algoritmo
        • +
        • podemos armar queries específicos (manipular SQL puro)
        • +
        +
      • +
      • Contras +
          +
        • hay que encargarse de todo: es tedioso y repetitivo
        • +
        • dificulta la reutilización de ideas
        • +
        +
      • +
      • Tests unitarios +
          +
        • el juego de datos se instancia “por afuera” +
            +
          • esto implica una dependencia que sale del ambiente de objetos
          • +
          • si alguien se olvida de correr el script en la base de datos, no funcionan los tests
          • +
          • si alguien cambia el juego de datos, no funcionan los tests
          • +
          • mientras nadie modifique la base, los tests funcionan
          • +
          • claro, no hay efecto colateral: los tests sólo son de lectura.
          • +
          +
        • +
        • Más adelante veremos técnicas para que los tests puedan seguir manteniendo unitariedad (e - independencia entre sí).
        • +
        +
      • +
      +
    • +
    • Resumen
    • +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/phm-script-mongodb.html b/wiki/articles/phm-script-mongodb.html new file mode 100644 index 0000000000..330e11e1a9 --- /dev/null +++ b/wiki/articles/phm-script-mongodb.html @@ -0,0 +1,321 @@ + + + + + + + + + + + Script temario MongoDB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/phm-temario.html b/wiki/articles/phm-temario.html new file mode 100644 index 0000000000..6528e1004b --- /dev/null +++ b/wiki/articles/phm-temario.html @@ -0,0 +1,313 @@ + + + + + + + + + + + Programacion con herramientas modernas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Programacion con herramientas modernas +

    +
    + + + +
    +

    Software

    + + + +

    Páginas

    + + + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/polimorfismo-en-el-paradigma-de-objetos.html b/wiki/articles/polimorfismo-en-el-paradigma-de-objetos.html new file mode 100644 index 0000000000..af31afe5d1 --- /dev/null +++ b/wiki/articles/polimorfismo-en-el-paradigma-de-objetos.html @@ -0,0 +1,351 @@ + + + + + + + + + + + Polimorfismo en el paradigma de objetos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Polimorfismo en el paradigma de objetos +

    +
    + + + +
    +

    El polimorfismo en el paradigma de objetos se define como la capacidad que tiene un objeto de poder tratar indistintamente a otros que sean potencialmente distintos. Cuando hablamos de que un objeto “trate” a otros, estamos hablando de que interactúen a través de mensajes.

    + +

    Lo que nos va a interesar al programar es ver a un objeto desde un punto de vista externo (cuando mandamos mensajes) y desde un punto de vista interno (cuando implementamos el comportamiento que queremos). Al punto de vista externo, que sólo incluye el comportamiento que exhibe (los mensajes que entiende) le vamos a decir interfaz.

    + +

    ¿Y Como puede un objeto tratar indistintamente (o a partir de ahora, polimorficamente) a otros?

    + +

    Mandandole los mismos mensajes!

    + +

    Entonces, podemos decir que un objeto trata polimórficamente a otros cuando les envía a ambos exactamente los mismos mensajes, sin importarle cual es cual y ellos pueden responder ya que tienen una interfaz común.

    + +
    + +

    ¿Cuántos objetos son necesarios como mínimo para que exista el polimorfismo?

    + +

    Tres: El objeto que “usa” y los (como mínimo) 2 que son “usados”.

    + +

    ¿Cuáles son las condiciónes necesarias para que dos objetos sean polimórficos?

    + +

    ’’ - que un tercero quiera usarlos indistintamente’’

    + +

    ’’ - que entiendan los mensajes que ese tercero quiere enviarles’’

    + +

    Cabe resaltar que para que dos objetos sean polimórficos en un contexto determinado (es decir, ante el tercero, en un momento particular), es condición necesaria que entiendan los mismos mensajes. Sin embargo, para que puedan ser usados indistintamente, además de ello, deben comportarse ante tal envío de mensaje, de una forma similar desde el punto de vista del dominio, produciendo efectos similares, devolviendo objetos también polimórficos entre sí, etc.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/polimorfismo-en-el-paradigma-logico.html b/wiki/articles/polimorfismo-en-el-paradigma-logico.html new file mode 100644 index 0000000000..0c4d47b5f0 --- /dev/null +++ b/wiki/articles/polimorfismo-en-el-paradigma-logico.html @@ -0,0 +1,523 @@ + + + + + + + + + + + Polimorfismo en el paradigma logico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Polimorfismo en el paradigma logico +

    +
    + + + +
    +

    El polimorfismo permite obtener soluciones más genéricas, que sean válidas para diferentes tipos de datos contemplando las particularidades de cada uno de ellos. En general podemos decir que dos cosas son polimórficas cuando desde algún punto de vista comparten un tipo, o sea que pueden ser tratados indistintamente por quienes no les interesen los detalles en los cuales difieren.

    + +

    Si bien todos los predicados pueden recibir cualquier tipo de argumento, muchas veces el uso que se hace de ellos en el interior de las cláusulas que lo definen, delimita un rango de tipos de valores que tiene sentido recibir. En lógico no sucede un error si se recibe un dato de tipo diferente a los esperados, sino que directamente la consulta falla por no poder unificar el valor recibido con lo esperado, descartándolo como posible respuesta a la misma.

    + +

    Ejemplo de Polimorfismo usando functores

    + +

    Si tenemos el siguiente requerimiento: “se tiene 3 tipos de vehiculos autos, camiones y bicicletas. Un auto es viejo si su patente es menor a F, un camion es viejo si tiene más de 60000km o más de 10 años, una bicicleta es vieja si la fecha de fabricacion es de año anterior al 2006”

    + +

    Supongamos que nuestra base de conocimiento tiene los siguientes hechos:

    + +
    hoy(fecha(22,12,2008)).
    +vehiculo(auto("A2000")).
    +vehiculo(auto("H2342")).
    +vehiculo(camion(12000,2005)).
    +vehiculo(camion(70000,2003)).
    +vehiculo(camion(30000,1997)).
    +vehiculo(bici(fecha(30,10,2005))).
    +vehiculo(bici(fecha(20,12,2008))).
    +
    + +

    Si quiero hacer una consulta que me diga si todos los vehículos de la base de conocimientos son viejos, ¿cómo hago para manejar el tema de que los datos tienen formas distintas y la lógica asociada a las distintas formas varía?

    + +

    La alternativa infeliz no polimórfica sería hacer algo así:

    + +
    autoViejo(Patente):- Patente > "F".
    +camionViejo(Kilometraje,_):- Kilometraje > 60000.
    +camionViejo(_,Anio):- hoy(fecha(_,_,AnioActual)),
    +                      AnioActual - Anio > 10.
    +biciVieja(fecha(_,_,Anio)):- Anio < 2006.
    +
    +?- forall(vehiculo(auto(Patente)), autoViejo(Patente)),
    +   forall(vehiculo(camion(Kms, Anio)), camionViejo(Kms, Anio)),
    +   forall(vehiculo(bici(Fecha)), biciVieja(Fecha)).
    +
    + +

    Para que esto se cumpla todos los vehículos deben cumplir la correspondiente validación del forall con lo cual estaría funcionando como necesitamos, pero la solución elegida es bastante molesta y repetitiva. Sin contar que si queremos incorporar las motos a nuestra base de conocimientos, la consulta sería aún más larga.

    + +

    La idea del polimorfismo nos viene bárbaro en este caso, y lo único que necesitamos es que exista un predicado esViejo/1 ande con autos, camiones y bicicletas y por ende pueda ser usado de forma genérica por otro predicado o consulta sin tener que pensar en el tipo de vehículo.

    + +

    Ahora, para resolver el requerimiento de forma polimórfica tenemos que hacer el predicado esViejo/1 que se verifique si se cumplen las condiciones explicadas anteriormente. Para ello usaremos varias cláusulas que, por medio de pattern matching, se apliquen a cada tipo de vehículo particular.

    + +
    esViejo(auto(Patente)):- Patente > "F".
    +esViejo(camion(Kilometraje,_)):- Kilometraje > 60000.
    +esViejo(camion(_,Anio)):- hoy(fecha(_,_,AnioActual)),
    +                          AnioActual - Anio > 10.
    +esViejo(bici(fecha(_,_,Anio))):- Anio < 2006.
    +
    + +

    Con esto podemos realizar la consulta que queríamos de esta forma:

    + +
    ?- forall(vehiculo(Vehiculo), esViejo(Vehiculo)).
    +
    + +

    Podemos decir entonces que el predicado polimórfico es esViejo/1, porque funciona con distintos tipos de vehiculos, y quien lo aprovecha es la consulta del forall que no necesita hacer distinciones sobre los tipos de vehículos, unificando toda la estructura con la variable Vehiculo.

    + +

    Es importante notar que modelar los vehículos con functores nos permite tener individuos más complejos a que si tuviéramos directamente los datos en el predicado:

    + +
    vehiculo(auto,"A2000").
    +
    + +

    Y además nos permite usar el mismo predicado (vehiculo/1 en este caso) para todos los tipos de vehículos, lo cual se aprovecha principalmente con el camión que tiene año y kilometraje:

    + +
    vehiculo(auto,"A2000").            % vehiculo/2
    +vehiculo(camion, 12000, 2005).     % vehiculo/3
    +
    + +

    Al tener distinta cantidad de valores afecta directamente a la aridad. Eso nos llevaría a trabajar con más de un predicado para la misma relación, que era el problema original. (Por más que se llamen igual, si la cantidad de parámetros es distinta, es otro predicado, ya que no hay forma de consultarlos a la vez).

    + +

    Errores comunes

    + +

    Repito lógica por hacer mal uso de polimorfismo

    + +

    Supongamos que tenemos la siguiente base de conocimiento:

    + +
    juguete(ingenio(cuboRubik,10)).
    +juguete(ingenio(encajar,2)).
    +juguete(munieco(50)).
    +juguete(peluche(300)).
    +juguete(peluche(150)).
    +
    + +

    Suponiendo que quiero saber si un juguete es caro, lo que sucede cuando su precio supera los 100 pesos.

    + +

    Se sabe que el precio de los juguetes de ingenio es de $20 por cada punto de dificultad, el precio del muñeco es el indicado, y el precio de los peluches es la mitad de su tamaño en mm.

    + +

    Una forma de resolverlo sería:

    + +
    esCaro(ingenio(_,Dificultad)):-
    +     100 < Dificultad * 20.
    +esCaro(munieco(Precio)):- 
    +     Precio > 100.
    +esCaro(peluche(Tamanio)):-
    +     Tamanio / 2 > 100.
    +
    + +

    El problema es que repito la lógica de cuándo un juguete es caro en las tres cláusulas, porque me falta abstraer la lógica del precio.

    + +

    Si tengo la lógica del precio delegada en otro predicado, luego no necesito repetir la lógica de esCaro en cada cláusula:

    + +
    esCaro(Juguete):-
    +     precio(Juguete,Precio),
    +     Precio > 100.
    +     
    +precio(ingenio(_,Dificultad), Precio):-
    +     Precio is Dificultad * 20.
    +precio(munieco(Precio),Precio).
    +precio(peluche(Tamanio),Precio):-
    +     Precio is Tamanio / 2.
    +
    + +

    Intento poner una variable en el nombre del functor

    + +

    Supongamos que tenemos un predicado que relaciona una patente con un vehículo, como la siguiente base de conocimiento:

    + +
    vehiculo(opp564, camion(mercedes,2014)).
    +vehiculo(agt445, auto(504,1995)).
    +vehiculo(mmr444, camion(scania,2010)).
    +
    + +

    Y quisiéramos saber las patentes de los autos anteriores al 2000. Lo siguiente es incorrecto:

    + +
    patenteDeAutoInteresante(Patente):-
    +   vehiculo(Patente, Tipo(_,Anio)),
    +   Anio < 2000.
    +
    + +

    ¿Por qué es incorrecto? Primero, Prolog no me deja usar el nombre del functor como un dato, que yo pueda poner en una variable ú operar. Además, lo siguiente no sería posible:

    + +
    vehiculo(ppt666, moto(2010)). % No respeta la aridad
    +vehiculo(ert434, lancha(2017,yamaha)). % El orden es otro
    +vehiculo(dfg345, karting(rojo)). % ¡Y puede ser que no incluya la información del año y haya que hacer otra cosa!
    +
    + +

    Por lo tanto, lo que deberíamos hacer es obtener el dato de año de alguna otra manera…

    + +

    Relaciones que repiten lógica

    + +

    … una forma podría ser relacionando el año con la patente:

    + +
    patenteDeAutoInteresante(Patente):-
    +   anioPatente(Patente, Anio),
    +   Anio < 2000.
    +
    + +

    El problema está en que estamos obligados a relacionar la patente con el vehículo para saber el año, repetida en cada cláusula de anioPatente/2:

    + +
    anioPatente(Patente, Anio):-
    +   vehiculo(Patente, moto(Anio)).
    +
    +anioPatente(Patente, Anio):-
    +   vehiculo(Patente, camion(_, Anio)).
    +   
    +anioPatente(Patente, Anio):-
    +   vehiculo(Patente, lancha(Anio, _)).
    +
    + +

    El problema está en que estamos relacionando la patente con un año, cuando eso depende del vehículo.

    + +

    relaciones

    + +

    Una posible solución

    + +

    La siguiente solución arregla todos los problemas mencionados arriba:

    + +
    patenteDeAutoInteresante(Patente):-
    +   vehiculo(Patente,Vehiculo),
    +   anioVehiculo(Vehiculo,Anio),
    +   Anio < 2000.
    +   
    +anioVehiculo(camion(_,Anio),Anio).
    +anioVehiculo(auto(_,Anio),Anio).
    +anioVehiculo(moto(Anio),Anio).
    +anioVehiculo(lancha(Anio,_),Anio).
    +anioVehiculo(karting(Color),Anio):- colorDelAnio(Color,Anio).
    +
    +colorDelAnio(rojo,2010).
    +colorDelAnio(verde,1990).
    +colorDelAnio(azul,2015).
    +
    + +

    De esta forma se evita repetir lógica creando relaciones acordes a los datos de los individuos, aprovechando el polimorfismo en patenteDeAutoInteresante/1 al unificar toda la estructura con Vehiculo (sin iportar su forma) y recién haciendo pattern matching cuando es necesario, en anioVehiculo/2.

    + +

    Así puedo meter los functores con la forma que yo quiera , y aún así mi predicado patenteDeAutoInteresante/1 no cambia. Esa es la gran ventaja del polimorfismo. Lo único que tengo que hacer es definir el predicado anioVehiculo/2 para ese nuevo tipo de functor, y ya todo anda ;)

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/polimorfismo-parametrico-y-ad-hoc.html b/wiki/articles/polimorfismo-parametrico-y-ad-hoc.html new file mode 100644 index 0000000000..7b299881f3 --- /dev/null +++ b/wiki/articles/polimorfismo-parametrico-y-ad-hoc.html @@ -0,0 +1,359 @@ + + + + + + + + + + + Polimorfismo parametrico y ad hoc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Polimorfismo parametrico y ad hoc +

    +
    + + + +
    +

    Primero que nada, cuando hablamos de polimorfismo nos referimos a la capacidad de una función de recibir por parámetro valores de distinto tipo. No es taaan importante esta clasificación en sí, pero lo explicamos para despejar dudas.

    + +

    Cuando hablamos de polimorfismo paramétrico tenemos una sola definición de la función, en cambio cuando tenemos polimorfismo ad-hoc tenemos muchas definiciones para la misma función de modo que se puedan soportar distintos tipos. Lo que normalmente hacemos (al menos en paradigmas) es definir funciones que son polimórficas paramétricamente, sin embargo sí usamos mucho funciones con polimorfismo ad-hoc.

    + +

    Típicas funciones con polimorfismo paramétrico son las que operan sobre listas: filter, map, all, any, length, foldl, etc. No necesariamente pueden recibir “cualquier valor”, depende de lo que hagas. Por ejemplo el tipo de length es

    + +

       [a] -> Int,

    + +

    con lo cual puede recibir una lista de cualquier cosa, pero el de sum es

    + +

       Num a => [a] -> a

    + +

    entonces sólo puede recibir una lista numérica (igual es polimórfica, porque hay muchos tipos de números, ver Typeclass Num).

    + +

    La suma también es una operación polimórfica y su tipo es:

    + +

       Num a => a -> a -> a

    + +

    Si te fijas bien no hay forma de diferenciarlos por el tipo, lo que cambia es que la suma está definida de forma diferente para cada tipo numérico (si se animan pueden buscarlo en el Prelude de Haskell), mientras que el sum tiene una única definición.

    + +

    Se puede ver que en ambos ejemplos de polimorfismo paramétrico una sola definición de la función sirve para todos los casos polimórficos, eso se da porque: - En el caso de length porque no hace nada específico con los elementos de la lista, entonces pueden ser cualquier cosa. - En el caso de sum porque se basa en la suma (+) que a su vez es una operación polimórfica.

    + +

    Y esto último también me parece interesante, una función paramétricamente polimórfica muchas veces se basa en otra que usa polimorfismo ad-hoc (no es la única forma pero es algo frecuente)…. ¿por qué es interesante esto?

    + +

    Bueno primero hay que ver, ¿quién saca ventaja del polimorfismo? Y si lo pensás, las funciones que usan polimorfismo ad-hoc no sacan gran ventaja del polimorfismo, si yo tengo que definir la suma para cada tipo numérico es lo mismo que hubiera hecho sin polimorfismo.

    + +

    El chiste es justamente que luego alguien basándose en eso puede hacer funciones que sirvan para todos los números, porque la suma sirve para todos los números. La suma (+) labura para el sum.

    + +

    Eso es equivalente a lo que pasa en objetos cuando decimos que “dos objetos son polimórficos para un tercero”, ¿quién saca ventaja? El tercero! - Que las golondrinas y los picaflores sean polimórficos a la hora de volar o comer no les da ventajas a las aves (ni a volar o comer), si no a los terceros que pueden hacerlos volar y comer indistintamente. - Que la suma funcione polimórficamente para reales y enteros no beneficia a la suma, sino a otras funciones que pueden sumarlos indistintamente.

    + +

    En fin… volviendo a lo que decía al principio, insisto en que lo importante no es “qué tipo de polimorfismo usa una función” o “cuál es la definición de polimorfismo ad-hoc” sino, para qué sirve, qué ventajas le da a mi programa, cómo se puede aprovechar el potencial del polimorfismo para hacer código más claro/extensible/robusto/ponga aquí su cualidad preferida.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/polimorfismo.html b/wiki/articles/polimorfismo.html new file mode 100644 index 0000000000..a74cabd1d1 --- /dev/null +++ b/wiki/articles/polimorfismo.html @@ -0,0 +1,334 @@ + + + + + + + + + + + Polimorfismo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Polimorfismo +

    +
    + + + +
    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/pom-algo2.xml b/wiki/articles/pom-algo2.xml new file mode 100644 index 0000000000..7c444c3b66 --- /dev/null +++ b/wiki/articles/pom-algo2.xml @@ -0,0 +1,156 @@ + + 4.0.0 + org.uqbar + NOMBRE DE TU PROYECTO + 1.0-RELEASE + + UTF-8 + + + + org.eclipse.xtend + org.eclipse.xtend.lib + 2.25.0 + + + org.mockito + mockito-core + 3.8.0 + + + org.junit.jupiter + junit-jupiter-engine + 5.7.1 + test + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + 11 + + + + + org.eclipse.xtend + xtend-maven-plugin + 2.25.0 + + + + compile + testCompile + + + ${project.build.directory}/xtend-gen/main + ${project.build.directory}/xtend-gen/test + + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.6 + + + + prepare-agent + + + + report + test + + report + + + + + + + org.eluder.coveralls + coveralls-maven-plugin + 4.3.0 + + + + + ${basedir}/target/coverage.xml + + + UTF-8 + travis-ci + ${env.TRAVIS_JOB_ID} + + + + + javax.xml.bind + jaxb-api + 2.2.3 + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.jacoco + jacoco-maven-plugin + [0.7.7,) + + prepare-agent + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + [1.9.1,) + + add-resource + add-source + add-test-resource + add-test-source + + + + + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + + + \ No newline at end of file diff --git a/wiki/articles/portal-del-investigador.html b/wiki/articles/portal-del-investigador.html new file mode 100644 index 0000000000..0dac8b129b --- /dev/null +++ b/wiki/articles/portal-del-investigador.html @@ -0,0 +1,328 @@ + + + + + + + + + + + Portal del investigador + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Portal del investigador +

    +
    + + + +
    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/possibly-incorrect-indentation-or-mismatched-brackets.html b/wiki/articles/possibly-incorrect-indentation-or-mismatched-brackets.html new file mode 100644 index 0000000000..05dde3eaaf --- /dev/null +++ b/wiki/articles/possibly-incorrect-indentation-or-mismatched-brackets.html @@ -0,0 +1,438 @@ + + + + + + + + + + + Possibly incorrect indentation or mismatched brackets + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Possibly incorrect indentation or mismatched brackets +

    +
    + + + +
    +

    El problema

    + +

    Un error muy común en Haskell, tanto para los que recién arrancan como para los más experimentados, es pifiarla con los enters, espacios o tabs. ¿Por qué? Haskell no usa llaves {} ni bloques do-end para delimitar secciones del código, sino que se basa en el uso de caracteres blancos (withespaces) para darse cuenta, por ejemplo, cuando termina una ecuación de una función.

    + +

    Entonces, si ponemos tabs, espacios, enters de menos o de más, obtendremos un sólo error:

    + +

    +  parse error: “possibly incorrect indentation or mismatched brackets” +

    + +

    Lo que significa: “che, revisá tus withespaces; mientras tanto no voy a intentar interpretar a tu código”

    + +

    La solución

    + +

    La solución al problema depende de dónde hayas pifiado. Veamos algunos casos comunes:

    + +

    Dejar espacios o tabs antes de la cabecera de la función

    + +

    La cabecera de la función debe arrancar justo “contra el margen”.

    + +

    Mal:

    + +

    +    f x = x + 1 +

    + +

    Bien:

    + +

    + f x = 1 +

    + +

    Poner enters de más entre dos ecuaciones de la misma función

    + +

    Las ecuaciones de una función deben estar siempre juntas, sin enters de más entre ellas

    + +

    Mal:

    + +

    f 0 = 0 +f x = x + 1

    + +

    Bien:

    + +

     f 0 = 0 + f x = x + 1

    + +

    Poner enters de más en una expresión larga

    + +

    A veces puede pasar que por un tema de legibilidad queremos partir escribir una sola expresion larga a lo largo de varias lineas (aunque en general, el problema ahí es que la expresión es larga por falta de delegación). El tema es que tenemos que ser muy claros en indicarle a Haskell que la expresión no terminó.

    + +

    Dos reglas:

    + +
      +
    • Si hacemos eso, en general vamos a tener que poner la expresión entre paréntesis
    • +
    • Y todo caso, debemos respetar la identación
    • +
    + +

    Mal:

    + +

    f x = max +          x +          1

    + +

    Mal:

    + +

    f x = (max +           x +1)

    + +

    Mal:

    + +

    f x = (max x  +1)

    + +

    Bien (multiples líneas)

    + +

    f x = (max +           x +           1)

    + +

    Bien (una sola línea)

    + +

    + f x = max x 1 +

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/precedencia-de-los-operadores-mas-comunes-en-haskell.html b/wiki/articles/precedencia-de-los-operadores-mas-comunes-en-haskell.html new file mode 100644 index 0000000000..282d78b7b2 --- /dev/null +++ b/wiki/articles/precedencia-de-los-operadores-mas-comunes-en-haskell.html @@ -0,0 +1,432 @@ + + + + + + + + + + + Precedencia de los operadores mas comunes en haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Precedencia de los operadores mas comunes en haskell +

    +
    + + + +
    +

    Definición en el Prelude

    + +

    La siguiente tabla muestra la precedencia de los operadores que más utilizamos en Haskell. A mayor número mayor precedencia. Por ejemplo, el operador + tiene mayor precedencia que <, por lo tanto si escribimos:

    + +
    3 < 4 + 5
    +
    + +

    se entiende como:

    + +
    3 < (4+5)
    +
    + +

    La tabla (simplificada) es la siguiente:

    + +
    -- Primero vienen las funciones prefijas (como even, map, etc.) y luego los chirimbolos:
    +infixr 9  .
    +infixl 9  !!
    +infixr 8  ^, ^^, **
    +infixl 7  *, /, `quot`, `rem`, `div`, `mod`, :, %
    +infixl 6  +, -
    +infixr 5  :
    +infixr 5  ++
    +infix  4  ==, /=, <, <=, >=, >, `elem`, `notElem`
    +infixr 3  &&
    +infixr 2  ||
    +infixr 0  $
    +
    + +

    Eso significa que el signo pesos (la función $) tiene muy poca precedencia, va a ser la “última” en considerarse. Y por el contrario las funciones prefijas (como el even o el abs) van a tener mucha precedencia. Entonces esta cuenta:

    + +
    abs 3 - 5 -- Se lee como "le resto 5 al valor absoluto de 3"
    +
    + +

    Debe leerse como “le resto 5 al valor absoluto de 3”, porque eso es lo que significa en Haskell, porque la aplicación prefija de abs tiene más precedencia que el -. El resultado de esa cuenta es (-2) (negativo).

    + +

    Lo mismo sucede acá:

    +
    4 > 2 * 3 -- Se lee como "quiero saber si el 4 es mayor a la multiplicación entre 2 y 3"
    +
    +

    Se lee así porque el > tiene menos precedencia que el *, entonces el * se hace primero

    + +

    Por último, para romper la precedencia se usan paréntesis. Si yo quiero decir “el valor absoluto de la resta entre 3 y 5” lo que debo hacer es:

    + +
    abs (3 - 5) -- Se lee como "el valor absoluto de la resta entre 3 y 5"
    +
    + +

    Uso del signo pesos ($) para evitar paréntesis

    + +

    Ver Uso del signo pesos en Haskell para ver cómo se aprovecha que el $ tenga tan poca precedencia.

    + +

    Bonus: Asociatividad

    + +

    Las palabras clave infixl e infixr permiten indicar la asociatividad del operador. Los operadores definidos con infixl asocian a izquierda, mientras que los infixr asocian a derecha. Por lo tanto, la expresión:

    + +
    3 + 4 + 5
    +
    + +

    Se evalúa como:

    + +
    (3 + 4) + 5
    +
    + +

    Ya que el operador asocia a izquierda. En cambio la expresión:

    + +
    2:3:4:[]
    +
    + +

    Se debe leer como:

    + +
    2:(3:(4:[]))
    +
    + +

    Ya que el operador asocia a derecha, al igual que la composición (.), por ejemplo:

    + +
    snd . head . filter even
    +
    + +

    Debe leerse como:

    + +
    snd . (head . filter even)
    +
    + +

    También puede notarse que todos los operadores tienen menor precedencia que la aplicación funcional, es decir que al ejemplo anterior podríamos definirlo completamente si agregamos los paréntesis alrededor de .:

    + +
    snd . (head . (filter even))
    +
    + +

    Los operadores definidos como infix no son asociativos, por ejemplo el operador de igualdad ==. Por lo tanto la expresión:

    + +
    a == b == c
    +
    + +

    No se entiende como (a == b) == c ni como a == (b == c); la expresión sin paréntesis es incorrecta.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/precedencia-de-mensajes.html b/wiki/articles/precedencia-de-mensajes.html new file mode 100644 index 0000000000..d6f8cbdb71 --- /dev/null +++ b/wiki/articles/precedencia-de-mensajes.html @@ -0,0 +1,384 @@ + + + + + + + + + + + Precedencia de mensajes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Precedencia de mensajes +

    +
    + + + +
    +

    Muchas veces nos encontramos en la situación de querer mandar varios mensajes en una misma sentencia, donde hay varios objetos involucrados. ¿Qué mensaje se evalúa primero? ¿Cuál será el objeto que finalmente sea pasado como parámetro?

    + +

    Ésto se ve con varios ejemplos:

    + +

      2 + 3 squared.

    + +

    ¿Cómo lo interpreto? ¿(2+3) al cuadrado? ¿2 + (3 al cuadrado)?

    + +

    Otro ejemplo:

    + +

      3 + 2 * 4

    + +

    ¿Cómo lo interpreto? ¿(3+2) * 4? ¿3 + (2*4)?

    + +

    Precedencia

    + +

    Bueno, antes de saber cómo evaluarlo, hay que recordar que existen 3 tipos de mensajes en Smalltalk:

    + +
      +
    1. Unarios: pepita energía
    2. +
    3. Binarios: 3 + 2
    4. +
    5. De Palabra Clave: pepita come: 20.
    6. +
    + +

    Así, de arriba para abajo, es la precedencia de los mensajes. Más arriba en la lista está el mensaje, más fuerza tiene para “atraer” al objeto que tiene al lado.

    + +

    ¿Y qué sucede si hay dos mensajes con igual precedencia?

    + +
      +
    • Se evalúa de izquierda a derecha.
    • +
    + +

    El ejemplo final

    + +

    La siguiente evaluación:

    + +

      2 raisedTo: 5 - 2 * 4 sqrt.   

    + +

    Devuelve 64…

    + +
      +
    • se evalúa 4 sqrt (da 2),
    • +
    • luego 5 - 2 (da 3),
    • +
    • luego 3 * 2 (da 6)
    • +
    • luego 2 raisedTo: 6
    • +
    + +

    Sí, no hay precedencia de operadores como estamos acostumbrados, con lo cual el - tiene la misma precedencia que el * ya que ambos son binarios.

    + +

    ¿Y si yo quiero que primero se haga la multiplicación?

    + +

    Uso paréntesis, como en cualquier otro lenguaje:

    + +

      2 raisedTo: 5 - (2 * 4 sqrt). 

    + +

    Así se restaría el resultado de multiplicar 2 por la raíz de 4 al 5, con lo cual estaríamos elevando 2 a la 1.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/preguntas-frecuentes-del-paradigma-logico.html b/wiki/articles/preguntas-frecuentes-del-paradigma-logico.html new file mode 100644 index 0000000000..22ffd397b1 --- /dev/null +++ b/wiki/articles/preguntas-frecuentes-del-paradigma-logico.html @@ -0,0 +1,341 @@ + + + + + + + + + + + Preguntas frecuentes del paradigma logico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Preguntas frecuentes del paradigma logico +

    +
    + + + +
    +

    “Agregar” elementos a una lista

    + +

    Pregunta

    + +

    Respuesta

    + +

    Acordate de que el paradigma lógico no tiene efectos colaterales, por lo tanto “agregar” un elemento a una lista no es algo que se pueda hacer…

    + +

    Sí puedo relacionar una lista con otra que tenga un elemento más:

    + +

    X = [Head|Tail]

    + +

    Va a unificar Head con la cabeza de X y Tail con la cola. Por lo tanto X tendrá un elemento más que Tail (que sería Head). Eso se puede usar tanto para conseguir una lista X con un elemento más que Tail como para obtener un Tail con un elemento X.

    + +

    Lo que nunca podrías hacer es:

    + +

    X = [Head|X]

    + +

    (Nótese que en los ejemplos se utiliza el igual de una forma que en un predicado probablemente no sería necesario. Casi casi casi siempre el igual está de más.)

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/preguntas-frecuentes.html b/wiki/articles/preguntas-frecuentes.html new file mode 100644 index 0000000000..666ad11020 --- /dev/null +++ b/wiki/articles/preguntas-frecuentes.html @@ -0,0 +1,383 @@ + + + + + + + + + + + Preguntas frecuentes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Preguntas frecuentes +

    +
    + + + +
    +

    Problemas con el entorno

    + +

    Estoy tratando de pasar algunas clases del tp de objetos y no puedo crear clases.

    + +

    #* Fijate que el nombre de la clase este en mayúsculas.

    + +

    Interpretación de errores

    + +

    Evalué mi código, me tiró un error y no sé lo que significa

    + +

    #* Don’t panic

    + +

    #* Leé el título de la ventana de error

    + +

    #* Si con eso no alcanza para entender, lee la cadena de mensajes que se fueron enviando (stacktrace). Cada línea del stacktrace dice:

    + +

    #**la clase del objeto receptor, si el receptor era una clase dice además class, por ejemplo Golondrina class

    + +

    #**entre paréntesis la clase en donde está definido el método que se ejecutó

    + +

    #**el mensaje enviado a ese objeto

    + +

    #*Si todavía no sabés qué fue, apretá Debug que te aporta mucha más información para entender qué pasó

    + +

    Mensajes más comunes:

    + +

    MessageNotUnderstood

    + +

    Problema: Se mandó un mensaje que el receptor no entiende.

    + +

    Posibles soluciones:

    + +
      +
    • Revisar que el objeto receptor fuera correcto (si es nil probablemente haya algo sin inicializar)
    • +
    • Revisar que no haya error de tipeo (el mensaje coincide con el nombre del método definido)
    • +
    • Revisar que el método esté definido en el lugar correcto (del lado de las instancias si es un método de instancia y del lado de la clase si el receptor es una clase)
    • +
    + +

    Un caso particular con el que se pueden encontrar es que un objeto de una clase de ustedes no entienda el mensaje #adaptToNumber:andSend:, lo cual puede surgir si como parámetro de una operación matemática no era un número (por ejemplo 3 + pepita).

    + +
    + +

    NonBooleanReceiver: proceed for truth

    + +

    Problema: Se le mandó a un objeto que no es booleano un mensaje de booleanos como ifTrue:ifFalse:

    + +

    Solución: Mirar el stacktrace, en algún momento va a aparecer: ClaseDelObjetoReceptor(Object)>>mustBeBoolean más abajo en el stacktrace debería aparecer un mensaje que definieron ustedes o DoIt si se envió desde el workspace. Darle doble click a ese mensaje para abrir el debugger y ver qué pasó.

    + +
    + +

    ***Error: This block accepts arguments, but was called with arguments***

    + +

    Problema: se evaluó un bloque con una cantidad de argumentos distinta de la esperada.

    + +

    Solución: Buscar en el stacktrace el método que definieron (o DoIt si fue directo desde el workspace) que evaluó el bloque con una cantidad incorrecta de parámetros.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/preparacion-de-un-entorno-de-desarrollo-groovy.html b/wiki/articles/preparacion-de-un-entorno-de-desarrollo-groovy.html new file mode 100644 index 0000000000..f299f3ae6d --- /dev/null +++ b/wiki/articles/preparacion-de-un-entorno-de-desarrollo-groovy.html @@ -0,0 +1,370 @@ + + + + + + + + + + + Preparacion de un entorno de desarrollo groovy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Preparacion de un entorno de desarrollo groovy +

    +
    + + + +
    +

    Download e instalación base

    + +
      +
    • Vas a la página https://github.com/groovy/groovy-eclipse y buscás el link de update que se adapte a la versión de tu Eclipse
    • +
    • En Help > Install New Software generás un nuevo update site en base al link del punto anterior
    • +
    • Componentes a instalar: +
        +
      • Extra Groovy Compilers, elegí la versión más reciente
      • +
      • Groovy-Eclipse
      • +
      • m2e Configurator for Groovy-Eclipse
      • +
      +
    • +
    • Y luego lo instalás (va a tardar un ratito)
    • +
    + +

    Ojo, no te confíes en usar el Eclipse Marketplace porque trae versiones anteriores del plugin.

    + +

    Luego hay que instalar el plugin de Maven, ahora sí desde el Eclipse Marketplace.

    + +
      +
    • Help > Eclipse Marketplace, buscás Maven, seleccionás “Maven Integration for Eclipse”, Install, Confirm
    • +
    + +

    Utilizar Groovy en otro IDE

    + + + +

    Documentación

    + + + + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/preparacion-de-un-entorno-de-desarrollo-java-8.html b/wiki/articles/preparacion-de-un-entorno-de-desarrollo-java-8.html new file mode 100644 index 0000000000..eda6e942cd --- /dev/null +++ b/wiki/articles/preparacion-de-un-entorno-de-desarrollo-java-8.html @@ -0,0 +1,338 @@ + + + + + + + + + + + Preparacion de un entorno de desarrollo java 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Preparacion de un entorno de desarrollo java 8 +

    +
    + + + +
    +
      +
    1. REDIRECT Preparación de un entorno de desarrollo Java
    2. +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/preparacion-de-un-entorno-de-desarrollo-java.html b/wiki/articles/preparacion-de-un-entorno-de-desarrollo-java.html new file mode 100644 index 0000000000..b79f4daca9 --- /dev/null +++ b/wiki/articles/preparacion-de-un-entorno-de-desarrollo-java.html @@ -0,0 +1,618 @@ + + + + + + + + + + + Preparacion de un entorno de desarrollo java + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Preparacion de un entorno de desarrollo java +

    +
    + + + + + +
    +

    + +

    + +

    Introducción

    + +

    Para realizar aplicaciones de complejidad mediana-grande en Java, es recomendable contar con un entorno de trabajo que contemple al menos:

    + +
      +
    • Una herramienta de versionado de fuentes
    • +
    • Una herramienta de manejo de dependencias
    • +
    • Un mecanismo para automatizar los procesos administrativos del desarrollo (test, release, deploy, etc)
    • +
    • Un entorno de programación que permita: +
        +
      • Ayudas a la detección temprana de errores, autocompleción, herramientas para navegar y buscar ágilmente dentro del código, etc.
      • +
      • Soporte para la realización de refactors automatizados
      • +
      • Integración con la mayor cantidad posible de las demás herramientas que utilizamos.
      • +
      +
    • +
    + +

    En este artículo se propone una configuración de entorno de trabajo que intenta cumplir con los anteriores objetivos. Las herramientas seleccionadas para eso son:

    + +
      +
    • Java Development Kit
    • +
    • Eclipse como entorno integrado de desarrollo
    • +
    • Git como repositorio de fuentes y herramienta de versionado
    • +
    • Maven como herramienta para manejar dependencias y automatizar diversos procesos administrativos.
    • +
    + +

    Adicionalmente se instalarán extensiones al entorno de desarrollo eclipse para integrarlo con git y maven.

    + +

    JDK (Java Development Kit)

    + +

    Contiene un compilador y una máquina virtual (el runtime) que traduce a código de máquina el código intermedio que genera el compilador (.java → COMPILADOR (javac.exe) → .class → VM (java.exe) → ejecutable final).

    + +

    Al tiempo de escribir este artículo la última versión estable es 1.8. Para el propósito aquí descripto es recomendable instalar la Standard Edition.

    + +

    Download e instalación base

    + +

    A continuación se detallan los pasos básicos de instalación según el sistema operativo que se esté utilizando. Luego de realizar este paso inicial se deberá pasar a la configuración del entorno.

    + +

    Este es el link de downloads.

    + +

    Desde ahí buscan el Latest Release y se descargan el JDK del sistema operativo que esté instalado en sus máquinas.

    + +

    Para más detalles adicionales a los que se encuentran en esta página, se puede consultar el manual de instalación de sun.

    + +

    Ubuntu

    + +

    Para instalarlo en Ubuntu se puede hacer:

    +
    +
    +
    +      $ sudo apt-get install openjdk-8-jdk
    +
    +    
    +
    +
    + +

    Para definir la versión por defecto, podés correr

    +
    +
    +
    +      $ sudo update-alternatives --config java
    +
    +    
    +
    +
    + +

    y definir la versión con la que vas a usar.

    + +

    Otros sistemas operativos

    + +

    Para otros sistemas operativos desde este link seguís la explicación paso por paso que se encuentra aquí.

    + +

    Documentación

    + + + +

    Eclipse

    + +

    La instalación del eclipse es muy sencilla: hay que bajar el que corresponda a su sistema operativo desde http://www.eclipse.org/downloads/ y descomprimirlo en su disco rígido. Posiblemente deseen crear un acceso directo para apuntar al ejecutable.

    + +

    A los efectos de los objetivos planteados en este artículo, se recomienda elegir la versión denominada “Eclipse IDE for Java EE Developers”.

    + +

    Esa versión pesa bastante. Si no van a utilizar las herramientas de programación web es posible utilizar la versión más liviana “Eclipse IDE for Java Developers”.

    + +

    Configuraciones adicionales

    + + + +

    Documentación

    + + + +

    Maven

    + +

    Para instalar Maven te recomendamos seguir las instrucciones de esta página

    + +

    Creación de un proyecto básico

    + +

    Una vez instaladas todas las herramientas, se puede crear un proyecto en esta plataforma siguiendo este tutorial (ojo, este es un tutorial básico, si necesitan usar otras tecnologías de presentación busquen los tutoriales en las páginas de las tecnologías correspondientes).

    + +

    Mavenizar un proyecto existente

    + +

    Si ya arrancaste tu proyecto y decidiste más tarde que necesitabas usar Maven, podés mavenizarlo de alguna de las siguientes maneras.

    + +

    Usando M2Eclipse

    + +
      +
    • Click derecho en el Proyecto
    • +
    + + + +
      +
    • Configure -> Convert to Maven Project
    • +
    + + + +
      +
    • Ingresar el groupId deseado. Preferentemente que sea el package name que se hayan definido antes, ej: org.uqbar.arena.exampes
    • +
    + + + +
      +
    • Finish
    • +
    + +

    Independientemente de si su proyecto respeta la estructura estándar de un proyecto Maven, lo van a tener configurado y funcionando. De hecho, si crean los directorios y mueven el paquete a src/main/java, Maven automágicamente lo va a detectar.

    + +
    +
    +
    +      .
    +├── src
    +│   └── main
    +│       ├── java
    +│       │   └── org
    +│       │       └── uqbar
    +│       │           └── arena
    +│       │               └── examples
    +│       │                    └── Main.java
    +│       └── resources
    +├── pom.xml
    +
    +    
    +
    +
    + + + +
      +
    • Probamos hacer una compilación e instalación local.
    • +
    + +

    Links útiles

    + + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/preparacion-de-un-entorno-de-desarrollo-scala.html b/wiki/articles/preparacion-de-un-entorno-de-desarrollo-scala.html new file mode 100644 index 0000000000..42b2510b92 --- /dev/null +++ b/wiki/articles/preparacion-de-un-entorno-de-desarrollo-scala.html @@ -0,0 +1,441 @@ + + + + + + + + + + + Preparacion de un entorno de desarrollo scala + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Preparacion de un entorno de desarrollo scala +

    +
    + + + +
    +

    Download e instalación base

    + +

    Hay varios IDEs para desarrollar con Scala, incluso podemos desarrollar sin un IDE (solamente necesitamos el compilador). De todos modos acá vamos a explicar cómo se puede armar un ambiente de desarrollo usando Eclipse y Maven (para manejo de dependencias).

    + +
      +
    • La opción más recomendada es trabajar con IntelliJ
    • +
    + +

    Creación de un proyecto Maven con Scala

    + +

    La configuración de un proyecto Scala para poder utilizar Maven es relativamente compleja y tiene varias sutilezas, principalmente para poder integrar ambas herramientas dentro del Eclipse. Por eso, recomendamos la utilización de este parent project que creamos con este objetivo específico:

    + +
    +
    +
    +         <parent>
    +       <groupId>org.uqbar-project</groupId>
    +       <artifactId>uqbar-scala-parent</artifactId>
    +       <version>1.3</version>
    +   </parent>
    +
    +    
    +
    +
    + +

    Para poder utilizar ese parent project necesario realizar previamente realizar las tareas indicadas en Configuración de Maven para poder utilizar las herramientas de Uqbar

    + +

    Este parent project realiza varias configuraciones:

    + +
      +
    • Agrega las dependencias con Scala y ScalaTest
    • +
    • Define src/main/scala como directorio default donde están los fuentes (y src/test/scala donde están los tests).
    • +
    • Le indica al maven que utilice el compilador de Scala.
    • +
    • Configura la integración con el Eclipse.
    • +
    + +

    Documentación

    + + + +

    Links de interés

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/problemas-comunes-con-los-tipos-numericos-de-haskell.html b/wiki/articles/problemas-comunes-con-los-tipos-numericos-de-haskell.html new file mode 100644 index 0000000000..beb9f6888a --- /dev/null +++ b/wiki/articles/problemas-comunes-con-los-tipos-numericos-de-haskell.html @@ -0,0 +1,474 @@ + + + + + + + + + + + Problemas comunes con los tipos numericos de haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Problemas comunes con los tipos numericos de haskell +

    +
    + + + +
    +

    Para salir del paso…

    + +

    Al programar en Haskell suele pasar que muy frecuentemente tenemos problemas con los tipos numéricos, en particular suele ocurrir al intentar hacer divisiones. Por ejemplo en el siguiente programa, la función promedio

    + +
    promedio xs = sum xs / length xs
    +
    + +

    Produce el siguiente error:

    + +
        • Could not deduce (Fractional Int) arising from a use of ‘/’
    +      from the context: Foldable t
    +        bound by the inferred type of
    +                   promedio :: Foldable t => t Int -> Int
    +        at main.hs:1:1-32
    +    • In the expression: sum xs / length xs
    +      In an equation for ‘promedio’: promedio xs = sum xs / length xs
    +
    + +

    El problema surge porque el Haskell tiene diferentes tipos de valores numéricos (enteros, reales, etc): un sistema de tipos muy estricto que hace que no sea sencillo mezclar los distintos tipos de valores en una misma operación.

    + +

    La versión corta es que length xs es un entero y la operación / no está definida para los números enteros.

    + +

    Solución en GHCi

    + +

    Es necesario convertir el resultado de length xs al tipo de datos adecuado, utilizando la función fromIntegral:

    + +
    division xs = sum xs / fromIntegral (length xs)
    +
    + +

    Esto funciona siempre que yo quiera hacer una división no-entera y uno de los parámetros (o ambos) es un entero. Para hacer divisiones enteras tenemos las funciones div y mod.

    + +

    Solución si utilizás pdepreludat con stack

    + +

    Es necesario convertir el resultado de length xs al tipo de datos adecuado, utilizando la función toFloat:

    + +
    division xs = sum xs / fromIntegral (length xs)
    +
    + +

    La historia completa

    + +

    ¿La división no está definida para los enteros?

    + +

    Para comprender la totalidad del problema, es necesario comprender el tipo de la función (/):

    + +
    Main> :t (/)
    +(/) :: Fractional a => a -> a -> a
    +
    + +

    Se puede ver que (/) es una función polimórfica, es decir que puede ser utilizada con diferentes tipos de datos. Sin embargo no puede ser utilizada con cualquier tipo de dato; la restricción es que el tipo tiene que ser instancia de la clase Fractional. En particular, los tipos enteros de Haskell (Int e Integer) no son instancias de Fractional, por lo tanto siempre que se tenga un valor de alguno de esos tipos deberá ser convertido utilizando la función fromIntegral.

    + +

    Con esa idea en mente, analizamos los tipos de las funciones del ejemplo de la sección anterior:

    + +
    Main> :t sum
    +sum :: Num a => [a] -> a
    +Main> :t length
    +length :: [b] -> Int
    +
    + +

    Y podemos concluir que sum no tendrá problemas, porque funciona para cualquier tipo numérico (por definición todas las instancias de Fractional son instancias de Num.

    + +

    En cambio la función length no es polimórfica en cuanto a su valor de retorno; aunque puede recibir cualquier tipo de lista, siempre devuelve un Int. Entonces el resultado de length no puede ser parámetro de (/).

    + +

    Algunos casos más complicados

    + +

    Supongamos que no utilizamos la función sum, y en cambio queremos definir la nuestra propia, de la siguiente manera:

    + +
    suma = foldr (+) 0
    +
    + +

    O bien (para no definir una que ya existe), podemos definir

    + +
    prod = foldr (*) 1
    +
    + +

    ¿Funcionan las siguientes definiciones?

    + +
    div2  xs = suma xs / fromIntegral (length xs)
    +floca xs = prod xs / fromIntegral (length xs)
    +
    + +

    Si intentamos hacer eso, obtendremos el siguiente error:

    + +
    ERROR `[`file:.\pruebas.hs:15`](file:.\pruebas.hs:15)` - Instance of Fractional Integer required for definition of div2
    +
    + +

    Para entender por qué se produce esto, debemos analizar nuevamente los tipos de suma y prod:

    + +
    Hugs> :t suma
    +suma :: [Integer] -> Integer
    +Main> :t prod
    +prod :: [Integer] -> Integer
    +
    + +

    Y como se puede ver devuelven valores de tipo Integer que, como dijimos antes, no es instancia de Fractional y por lo tanto no funciona.

    + +

    La idea de la sección anterior también puede servir en este caso (aunque no es la única forma):

    + +
    div2  xs = fromIntegral (suma xs) / fromIntegral (length xs)
    +floca xs = fromIntegral (prod xs) / fromIntegral (length xs)
    +
    + +

    Aprovechando mejor el polimorfismo

    + +

    En realidad hay una forma mejor de solucionar el problema planteado en la sección. La desventaja de la solución descripta consiste en que, al resolverlo de esa manera, la función suma sólo funciona para valores de tipo Integer; lo que puede resultar muy restrictivo en un futuro.

    + +

    ¿Por qué sucede esto? Como sabemos, Haskell trabaja con inferencia de tipos, por lo tanto, cuando nosotros no indicamos en nuestro programa de qué tipo son los valores que espera y devuelve una función, el sistema intentará descubrir ese tipo por nosotros. Normalmente este mecanismo de inferencia es suficiente y resulta de gran utilidad, ya que nos permite tener un lenguaje fuertemente tipado que nos ayuda a encontrar muchos errores en nuestro código en una fase previa a la ejecución del programa, al mismo tiempo que nos evita de la burocracia y el engorro de tener que indicar el tipo de cada función explícitamente.

    + +

    Sin embargo en este caso el tipo inferido por el sistema de tipos de Haskell es subóptimo. El tipo inferido es [Integer] -> Integer, es decir, que sólo funciona para listas de tipo Integer.

    + +

    Sin embargo, si miramos la definición de suma, podemos ver que se basa en las funciones foldr y (+), cuyos tipos son:

    + +
    Main> :t foldr
    +foldr :: (a -> b -> b) -> b -> [a] -> b
    +Main> :t (+)
    +(+) :: Num a => a -> a -> a
    +
    + +

    Es decir que no hay ningún motivo para restringir el tipo a [Integer] -> Integer, dado que foldr funciona para cualquier tipo de lista y (+) funciona para todos los tipos de la familia Num (es decir, todos los tipos numéricos predefinidos del Haskell). De hecho, si consultamos el tipo de la expresión foldr (+) 0, obtenemos:

    + +
    Main> :t foldr (+) 0
    +foldr (+) 0 :: Num a => [a] -> a
    +
    + +

    que es el tipo que buscamos.

    + +

    Lamentablemente, cuando intenta inferir un tipo automáticamente para la función suma, Haskell le asigna un tipo monomórfico, defaulteando en el tipo Integer. La forma de evitar esta restricción es haciendo explícita nuestra intención de que la función suma sea polmórfica, esto se logra asociando a la función una indicación del tipo esperado.

    + +

    El tipo esperado no es otro que el de la expresión foldr (+) 0, es decir, Num a => [a] -> a. La definición de la función quedaría así:

    + +
    suma :: Num a => [a] -> a
    +suma = foldr (+) 0
    +
    + +

    Al hacer ese cambio la siguiente definición pasa a estar correctamente tipada:

    + +
    -- con GHCi
    +div2  xs = suma xs / fromIntegral (length xs) 
    +-- con pdepreludat y stack ghci
    +div2  xs = suma xs / toFloat (length xs) 
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/prototipado-vs-clases.html b/wiki/articles/prototipado-vs-clases.html new file mode 100644 index 0000000000..435cbad736 --- /dev/null +++ b/wiki/articles/prototipado-vs-clases.html @@ -0,0 +1,401 @@ + + + + + + + + + + + Prototipado vs clases + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Prototipado vs clases +

    +
    + + + +
    +

    En el paradigma orientado a objetos, cuando se suscita el problema de que existan diferentes objetos con igual comportamiento pero diferente identidad y estado interno, podemos abordarlo de diferentes formas. Dos esquemas muy usados son el de clases y el que se basa en prototipos. Cada lenguaje (o herramienta) suele implementar una sóla de éstas opciones, aunque existen variaciones. Los lenguajes más tradicionales (como Java, Smalltalk, y C#) usan el esquema de clases y herencia, y en otros lugares (como Javascript, ó en el Object Browser para Smalltalk), se usa el esquema de prototipado.

    + +

    Más allá de cuál de estos esquemas usemos, la base es la misma: objetos que se mandan mensajes en un ambiente aprovechando las ideas de encapsulamiento, delegación y polimorfismo.

    + +

    La idea de este artículo es ver cómo se puede trabajar en cada esquema para solucionar los mismos problemas.

    + +

    Compartir comportamiento entre varios objetos

    + +

    ¿Qué pasa si pepita no es la única golondrina que nos interesa tener en nuestro programa?. También están josefa y pepona que comen y vuelan como pepita y también deben tener una energía que podamos monitorear. Estaría bueno que josefa y pepona puedan tener el mismo comportamiento que pepita sin tener que definir lo mismo 3 veces. Aquí es donde entran los conceptos de clase y de prototipo, dependiendo de las herramientas que tengamos disponibles.

    + +

    Cuando existe la idea de clase en nuestra implementación del paradigma, el comportamiento se define una sola vez en la clase y tanto pepita como josefa y pepona pasan a ser instancias de esta clase. No podemos sólo tener a pepita con su propio código porque todos los objetos son instancias de una clase que las define. Cuando cualquiera de las golondrinas reciba el mensaje vola:, lo van a entender y buscarán el método que lo define en la clase Golondrina.

    + +

    Si no tenemos la idea de clase, el mecanismo que necesitamos para que josefa y pepona compartan el código con pepita es la colonación. Clonando a pepita podemos crear un nuevo objeto (josefa) que entiende los mismos mensajes y tiene sus mismas variables, y además conoce a pepita como su prototipo.

    + +

    Si queremos cambiar el comportamiento general de las golondrinas alcanza con realizar estos cambios sobre la clase Golondrina o sobre el prototipo pepita. Al decir que un objeto es clon de otro estamos estableciendo una relación tan fuerte entre ellos como al decir que un objeto es instancia de una clase al trabajar en el otro esquema.

    + +

    Diferenciar el comportamiento de algunos objetos

    + +

    Supongamos que pepona es otro clon de pepita. Queremos que pepona (que es una golondrina perezosa) entienda el mensaje descansar, que hace subir su energía en 50 joules. Sin embargo pepita y josefa que son golondrinas normales deberían seguir teniendo el mismo comportamiento (no entenderían descansar).

    + +

    En el esquema de prototipado podemos simplemente modificar a pepona como lo haríamos con cualquier otro objeto, sin importar si fue clonado a partir de pepita o no.

    + +

    #pepona  +>> descansar +  energia := energia + 50

    + +

    Cuando mandemos el mensaje pepona descansar lo va a entender (ya que tiene un método propio para este mensaje), va a ejecutar su método descansar y su energía se incrementará. Si mandáramos pepita descansar tendríamos un error porque pepita no entendería ese mensaje.

    + +

    ¿Qué pasaría si estuviéramos trabajando con el esquema de clases? Siempre que aparece comportamiento nuevo, necesitamos crear otra clase que lo incluya, con lo cual necesitaríamos crear una clase GolondrinaPerezosa que herede de Golondrina y definir allí el método #descansar. De esta forma, pepona ya no debería ser una instancia de Golondrina sino de GolondrinaPerezosa.

    + +

    pepona := GolondrinaPerezosa new. +pepona descansar. "esto va a funcionar" +pepita := Golondrina new. +pepita descansar. "pepita no va a entender el mensaje descansar"

    + +

    Si lo que queremos es agregar algún atributo nuevo para pepona, estaríamos en la misma situación, habría que agregarlo en el objeto #pepona o en la clase GolondrinaPerezosa respectivamente.

    + +

    Redefinir comportamiento

    + +

    Siguiendo con pepona, la golondrina perezosa, sabemos que cuando vuela gasta más energía para despegar (15 en vez de 10). Una primer solución podría ser redefinir el método vola:

    + +

    #pepona / #GolondrinaPerezosa +>> vola: unosKilometros +  energia := energia - (unosKilometros * 5 + 15)

    + +

    Cuando le mandemos el mensaje pepona vola: 10, buscará una definición propia (o en su clase) para vola: y al encontrarla ejecutará ese método. Haber agregado este método no cambia el comportamiento de pepita y josefa, que es lo que queríamos.

    + +

    Sin embargo podríamos dar un paso más para evitar la repetición de código, siendo que lo único que cambia es el valor de la energía para despegar. Una solución mejor sería:

    + +

    #pepita / #Golondrina +>> vola: unosKilometros +  energia := energia - (unosKilometros * 5 + self energiaParaDespegar) +>> energiaParaDespegar +  ^ 10 +#pepona / #GolondrinaPerezosa +>> energiaParaDespegar +  ^ 15

    + +

    Ahora, cuando le mandemos el mensaje pepona vola: 10, buscará una definición propia (o en su clase) para vola:, no la va a encontrar, con lo cual seguirá buscando en su prototipo (o la superclase de su clase) donde sí existe. Al ejecutar esa definición, se enviará a sí misma el mensaje #energiaParaDespegar; empieza a buscar un método con ese nombre en sí misma (o en su clase GolondrinaPerezosa), lo encuentra y retorna 15, valor que se usará para completar la ejecución de vola:

    + +

    Si le mandamos el mensaje pepita vola: 10, encontrará y ejecutará la definición en sí misma (o en su clase Golondrina) al igual que para el mensaje #energiaParaDespegar que retornará el valor 10.

    + +

    Conclusión / Corolarios

    + +
      +
    • Al solucionar el problema utilizando abstracciones ya existentes, prototipado es conceptualmente más sencillo
    • +
    • Entonces, el mecanismo de clases agrega una abstracción, ya no tengo sólo “objetos comunes”.
    • +
    • Además, prototipado me resuelve el problema de redefinición sin más conceptos, en cambio en clases yo tengo que agregar la idea de herencia entre las clases para lograr algo parecido.
    • +
    • Por otro lado, la separación objeto - clase viene asociada con un mecanismo para conocer a las clases “globalmente”, mientras que si uso prototipado tengo que preocuparme por guardar el prototipo de mis objetos en algún lado
    • +
    • Si bien en prototipado se puede usar a prototype para delegar, esto no es lo mismo que usar super al usar herencia, ya que prototype referencia a otro objeto (con su propio estado) mientras que super referencia al mismo objeto que recibió el mensaje inicial
    • +
    • En prototipado, el “contenedor” de comportamiento es dinámico, es un objeto más de mi sistema. Al usar clases, en muchos lenguajes la separación “clase - objeto” es tal que pertenecen a dos mundos diferentes, el “estático” y el “dinámico”.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/prototipado.html b/wiki/articles/prototipado.html new file mode 100644 index 0000000000..60926ad2c4 --- /dev/null +++ b/wiki/articles/prototipado.html @@ -0,0 +1,388 @@ + + + + + + + + + + + Prototipado + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Prototipado +

    +
    + + + +
    +

    Un prototipo según la RAE es un “Ejemplar original o primer molde en que se fabrica una figura u otra cosa.” Este término se utiliza en la programación orientada a objetos para aquellos objetos que sirven como base para obtener otros objetos como él, la forma de obtener nuevos objetos a partir del prototipo se denomina clonación.

    + +

    ¿Qué problema es el que resuelve la clonación, entonces?

    + +

    Si ya existe un objeto con un determinado comportamiento y estado interno y lo clonamos, obtendremos otro objeto con el mismo comportamiento (entiende los mismos mensajes y se definen de la misma forma) y estado interno (comparte la forma, pero cada objeto tiene sus propias referencias, ya que queremos que el estado de cada objeto sea independiente) que el original.

    + +

    ¿Qué significa ésto? Que si queremos que todas las golondrinas del universo coman y vuelen de la misma forma (pero que cada una tenga su propia energía), entonces podemos hacer que todas sean clones de “pepita”, nuestra golondrina original, la que usaremos como prototipo.

    + +

    La principal diferencia entre clonar un objeto y crear otro copiando el código que ya teníamos es que el código no está duplicado. Al decir que un objeto es clon de otro estamos estableciendo una relación fuerte entre ellos; si se agrega, quita o modifica algún método en el prototipo, todos sus clones se verán afectados por este cambio, lo cual lógicamente no sucede si duplicamos código, tendríamos que hacer los cambios en cada lugar que esté repetido pudiendo olvidar hacer alguno o cometer errores fácilmente. Lo mismo sucederá si le agregamos o quitamos alguna referencia al prototipo, el mismo cambio se hará sobre sus clones. Donde apunte la referencia en cada clon será probablemente diferente.

    + +

    Volviendo sobre el ejemplo de pepita la golondrina, supongamos que queremos clonarla para crear otra golondrina, josefa.

    + +

    Si teníamos el siguiente código en el objeto pepita:

    + +

    #pepita +>> vola: unosKilometros +  "Gasta 5 joules por kilómetro más 10 de despegue" +  energia := energia - (unosKilometros * 5 + 10)

    + +

    Y le mandamos a josefa

    + +

    josefa vola: 10.

    + +

    El objeto josefa buscará la implementación de vola: en sí mismo inicialmente, y al no tener una definición propia, la seguirá buscando en su prototipo que es pepita. Allí encuentra una definición y la ejecuta. La energía que va a disminuir es la de josefa, el estado interno de pepita se va a mantener intacto.

    + +

    También podríamos tener una definición de vola: usando mensajes a self en vez de accediendo directamente a la variable energía:

    + +

    #pepita +>> vola: unosKilometros +  self energia: self energia - (unosKilometros * 5 + 10)

    + +

    Como self siempre es el objeto receptor del mensaje, si vola: se lo mandamos a josefa, self estará referenciando a josefa, no a pepita.

    + +

    Lógicamente, si le mandamos vola: a pepita, va a entender el mensaje, a ejecutar su propia definición de vola: y modificar su propia energia sin afectar a ninguno de sus clones.

    + +

    Una vez que tenemos el objeto clonado podemos trabajar con él modificando su comportamiento y su estado interno, con lo cual podremos mantener las similitudes con su prototipo en aquellos puntos en los cuales nos interese e introducir diferencias en otros. Si el prototipo define un método para el mensaje #msj1 y el clon cambia su implementación, el prototipo no se verá afectado por este cambio y el clon usará su propia implementación cuando reciba #msj1 en vez de usar la del prototipo.

    + +

    A modo resumen podemos decir que el method lookup al usar prototipado se resuelve de la siguiente forma:

    + +

    Tenemos el objeto o1 cuyo prototipo es o2, y o1 recibe el mensaje #m

    + +
      +
    • o1 tiene un método cuyo nombre es #m, se ejecuta ese método.
    • +
    • o1 no tiene un método cuyo nombre es #m, entonces busca una definición en su prototipo +
        +
      • o2 tiene un método cuyo nombre es #m, se ejecuta ese método (el receptor sigue siendo o1)
      • +
      • o2 no tiene un método cuyo nombre es #m, con lo cual habrá un error porque o1 no entiende el mensaje #m
      • +
      +
    • +
    + +

    Si o2 a su vez tuviera otro prototipo, el method lookup continuaría hasta que se llegue a un objeto que no es clon de ningún otro.

    + +

    Para descargar la herramienta que soporta prototipado en Pharo Smalltalk y tutoriales de uso: Object Browser (LOOP)

    + +

    Ejemplo completo

    + +

    Prototipado.png

    + +

    Nota: El ejemplo de Pepita es obra de Carlos Lombardi. Cualquier reproducción del mismo deberá ser autorizada por el autor.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/pseudovariable.html b/wiki/articles/pseudovariable.html new file mode 100644 index 0000000000..c6a55cdfed --- /dev/null +++ b/wiki/articles/pseudovariable.html @@ -0,0 +1,317 @@ + + + + + + + + + + + Pseudovariable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Pseudovariable +

    +
    + + + +
    +

    Una pseudovariable es un variable manejada por el ambiente, dicha variable no puede ser asignada a otro valor.

    + +

    En Smalltalk las 2 pseudovariables más usadas son self y super

    + +

    En Wollok contamos solo con self (en realidad existe super, pero no como pseudovariable, si no como una palabra reservada, con un significado especial).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/publicar-un-proyecto-en-svn.html b/wiki/articles/publicar-un-proyecto-en-svn.html new file mode 100644 index 0000000000..46cf596f26 --- /dev/null +++ b/wiki/articles/publicar-un-proyecto-en-svn.html @@ -0,0 +1,349 @@ + + + + + + + + + + + Publicar un proyecto en svn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Publicar un proyecto en svn +

    +
    + + + +
    +

    Antes de publicar un proyecto es (obviamente) necesario tener un usuario y un repositorio svn, una forma de hacer eso es Crear un proyecto en xp-dev

    + +

    Desde el Eclipse:

    + +

    Botón derecho sobre el proyecto -> Team -> Share Project y ahí poner la url del repositorio donde esta el proyeto seguido de . Por ejemplo:

    + +
    http://svn2.xp-dev.com/svn/nombre_del_repositorio/nombre_del_proyecto/trunk
    +
    +

    Esto va a crear la carpeta del proyecto y/o trunk si no existen.

    + +

    Este paso nos lleva a la perspectiva Synchronize del eclipse donde tenemos que comitear para guardar en el trunk nuestros sources del proyecto. En este momento, antes de comitear tenemos que indicarle al svn los archivos y carpetas que no queremos versionar, para esto, le damos botón derecho -> Add to .

    + +

    Lo que tenemos que agregar al en un proyecto simple es:

    + +
      +
    • la carpeta que guarda información del eclipse
    • +
    • la carpeta que es donde estan los compilados
    • +
    • el y el
    • +
    + +

    **Recordemos que siempre ponemos en el todo aquello que se genera automáticamente, en este caso, todos estos archivos los genera el maven.**

    + +

    Entonces ahora que ya le dijimos al svn que es lo que no queremos versionar, estamos en condiciones de comitear. Botón derecho sobre el proyecto -> Commit.

    + +

    Después hay que crear las carpetas branches y tags en el repositorio.

    + +

    Desde la consola:

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/python.html b/wiki/articles/python.html new file mode 100644 index 0000000000..fb1efe6370 --- /dev/null +++ b/wiki/articles/python.html @@ -0,0 +1,319 @@ + + + + + + + + + + + Python + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Python +

    +
    + + + +
    +

    Sobre el lenguaje:

    + + + +

    Herramientas basadas en Python:

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/que-entendemos-por-programacion-orientada-a-objetos-.html b/wiki/articles/que-entendemos-por-programacion-orientada-a-objetos-.html new file mode 100644 index 0000000000..add127a113 --- /dev/null +++ b/wiki/articles/que-entendemos-por-programacion-orientada-a-objetos-.html @@ -0,0 +1,285 @@ + + + + + + + + + + + que entendemos por programacion orientada a objetos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + que entendemos por programacion orientada a objetos +

    +
    + + + +
    +

    Hay muchas visiones sobre lo que significa “orientado a objetos”, que llevan a múltiples discusiones. En esta página hay una definición posible http://wcook.blogspot.com.ar/2012/07/proposal-for-simplified-modern.html

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/react-instalacion.html b/wiki/articles/react-instalacion.html new file mode 100644 index 0000000000..9ddd2e5fa0 --- /dev/null +++ b/wiki/articles/react-instalacion.html @@ -0,0 +1,878 @@ + + + + + + + + + + + Instalacion de ReactJS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Instalacion de ReactJS +

    +
    + + + + + +
    +

    + +

    + +

    Pasos previos

    + +

    Si ya estuviste trabajando con Angular estos pasos no son necesarios, pero conviene verificar que ya estén instalados.

    + +
      +
    • Si estás en entorno Windows te recomendamos instalarte Git Bash
    • +
    • Seguimos con NodeJS, preferentemente la última versión (tiene que ser 20.4.0 ó superior).
    • +
    • Luego NPM (Node Package Manager), con el que vamos a hacer los builds de nuestras aplicaciones.
    • +
    • El editor de texto que vamos a soportar en la cursada es Visual Studio Code (hay una versión portable si estás en una máquina sin privilegios de administrador).
    • +
    + +

    Específicos de React

    + +

    Plugins Visual Studio Code

    + +

    Dentro de Visual Studio Code, las extensiones que recomendamos para trabajar con React deberían ser las mismas con las que trabajaste en Angular y además revisar que tengas:

    + +
      +
    • ESLint - Microsoft
    • +
    • Prettier - ESLint - Rebecca Vest
    • +
    • y además Vitest - Zixuan Chen
    • +
    + +

    Crear un proyecto React de cero

    + +

    Para crear un proyecto React desde la consola Git Bash o bien desde una terminal Linux escribimos:

    + +
    +
    +
    +      npm create vite@latest nombre-del-proyecto
    +
    +    
    +
    +
    + +

    Y luego

    + +
      +
    • ✔ Select a framework: › React: seleccionar React como framework de UI
    • +
    • ✔ Select a variant: › Javascript + SWC: elegir la variante Javascript con SWC (herramienta de reemplazo de Babel)
    • +
    + +

    También podés usar el template directo React + Javascript + SWC (eso evita que tengas que seleccionar el tipo de proyecto):

    + +
    +
    +
    +      npm create vite@latest nombre-de-proyecto -- --template react-swc
    +
    +    
    +
    +
    + +

    Por defecto la aplicación cliente levantará en el puerto 5173. Como suele quedarse levantada aun cuando canceles la línea de comando y el navegador, te dejamos este link que te dice cómo bajar el proceso del sistema operativo para correr otro ejemplo.

    + +

    Configuraciones adicionales para Algoritmos III

    + +

    Una vez creado el proyecto, te recomendamos que agregues estas configuraciones.

    + +

    Agregar dependencias

    + +

    Agregamos estas dependencias de Prettier y Vitest (el framework de testing)

    + +
    +
    +
    +      npm i @testing-library/react @testing-library/jest-dom @testing-library/user-event @vitest/coverage-v8 @vitejs/plugin-react jsdom prettier vitest -D
    +
    +    
    +
    +
    + +

    Archivo .nvmrc

    + +

    Tener un archivo .nvmrc es conveniente si todo el equipo trabaja con NVM (el versionador de Node). El contenido especifica qué versión de Node vamos a utilizar:

    + +
    +
    +
    +      20.4.0
    +
    +    
    +
    +
    + +

    Archivos útiles

    + +

    En la carpeta raíz creá los siguientes archivos

    + +
      +
    • .markdownlint.json (configuración del Linter para archivos con extensión .md), con el siguiente contenido
    • +
    + +
    +
    +
    +      {
    +  "MD013": false,
    +  "MD024": false,
    +  "MD025": false
    +}
    +
    +    
    +
    +
    + +
      +
    • .prettierrc (configuración de Prettier para eliminar puntos y coma, definir tab de 2 espacios, utilizar single quote, etc.) Es importante que tod@s tengan esta configuración para que no haya un montón de conflictos en git a la hora de pushear.
    • +
    + +
    +
    +
    +      {
    +  "trailingComma": "all",
    +  "tabWidth": 2,
    +  "semi": false,
    +  "singleQuote": true
    +}
    +
    +    
    +
    +
    + +

    Linter para javascript

    + +

    El archivo .eslintrc.cjs debe tener la siguiente configuración:

    + +
    +
    +
    +      module.exports = {
    +  root: true,
    +  env: { browser: true, es2020: true },
    +  extends: [
    +    'eslint:recommended',
    +    'plugin:react/recommended',
    +    'plugin:react/jsx-runtime',
    +    'plugin:react-hooks/recommended',
    +  ],
    +  ignorePatterns: ['dist', '.eslintrc.cjs'],
    +  parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
    +  settings: { react: { version: '18.2' } },
    +  plugins: ['react-refresh'],
    +  rules: {
    +    'semi': ['error', 'never'],
    +    'prefer-const': [
    +      'warn',
    +      {
    +        'destructuring': 'any',
    +        'ignoreReadBeforeAssign': false
    +      }
    +    ],
    +    'getter-return': ['error'],
    +    'no-async-promise-executor': ['warn'],
    +    'no-cond-assign': ['warn', 'except-parens'],
    +    'no-dupe-keys': ['error'],
    +    'no-empty': ['warn'],
    +    'no-ex-assign': ['error'],
    +    'no-extra-boolean-cast': [
    +      'error',
    +      {
    +        'enforceForLogicalOperands': true
    +      }
    +    ],
    +    'no-extra-parens': ['warn', 'all'],
    +    'no-func-assign': ['error'],
    +    'no-import-assign': ['error'],
    +    'no-inner-declarations': ['error', 'both'],
    +    'no-obj-calls': ['error'],
    +    'no-promise-executor-return': ['error'],
    +    'no-sparse-arrays': ['error'],
    +    'no-template-curly-in-string': ['error'],
    +    'no-unreachable': ['error'],
    +    'no-unreachable-loop': ['error'],
    +    'no-unsafe-optional-chaining': ['error'],
    +    'require-atomic-updates': ['error'],
    +    'use-isnan': ['error'],
    +    'block-scoped-var': ['error'],
    +    'consistent-return': ['error'],
    +    'default-param-last': ['warn'],
    +    'no-alert': ['error'],
    +    'no-caller': ['error'],
    +    'no-constructor-return': ['error'],
    +    'no-global-assign': ['error'],
    +    'no-lone-blocks': ['warn'],
    +    'no-multi-spaces': ['warn'],
    +    'no-new': ['warn'],
    +    'no-param-reassign': ['error'],
    +    'no-proto': ['warn'],
    +    'no-redeclare': ['error'],
    +    'no-return-assign': ['error'],
    +    'no-return-await': ['warn'],
    +    'no-self-assign': ['error'],
    +    'no-sequences': ['warn'],
    +    'no-useless-catch': ['warn'],
    +    'no-useless-return': ['error'],
    +    'no-void': ['error'],
    +    'no-with': ['error'],
    +    'no-undef': ['off'],
    +    'react/display-name': ['off'],
    +    'react/jsx-uses-react': 'off',
    +    'react/react-in-jsx-scope': 'off',
    +    'react-refresh/only-export-components': [
    +      'warn',
    +      { allowConstantExport: true },
    +    ],
    +  },
    +}
    +
    +    
    +
    +
    + +

    Configuración del proyecto

    + +

    Al archivo package.json le modificamos el script lint y le agregamos test y coverage (borrale los comentarios porque no están permitidos en json):

    + +
    +
    +
    +        "scripts": {
    +    "lint": "eslint --cache --fix .", // modificar
    +    ...
    +    // agregar
    +    "test": "vitest",
    +    "coverage": "vitest run --coverage"
    +  },
    +
    +    
    +
    +
    + +

    .gitignore

    + +

    Al archivo .gitignore se le pueden incorporar estas líneas:

    + +
    +
    +
    +      # VSC - Git Lens
    +.history
    +
    +    
    +
    +
    + +

    Archivo de configuración para Visual Studio Code

    + +

    Te recomendamos que dentro del proyecto crees una carpeta .vscode y dentro un archivo settings.json que tenga este contenido:

    + +
    +
    +
    +      {
    +    "editor.codeActionsOnSave": { "source.fixAll.eslint": true },
    +    "editor.formatOnSave": true, 
    +    "files.autoSave": "onFocusChange" 
    +}
    +
    +    
    +
    +
    + +

    Configuración para el testeo unitario de frontend

    + +

    Hay que definir un archivo setupTests.js en el raíz de nuestro proyecto, que tenga el siguiente contenido:

    + +
    +
    +
    +      import "@testing-library/jest-dom/vitest"
    +
    +    
    +
    +
    + +

    El archivo vite.config.js contiene la configuración que necesitamos para ejecutar los tests, es importante agregar un reporter de tipo json-summary para que el build de Github Actions cree el badge con el % de cobertura automáticamente:

    + +
    +
    +
    +      /// <reference types="vitest" />
    +/// <reference types="vite/client" />
    +
    +import { defineConfig } from 'vite'
    +
    +import react from '@vitejs/plugin-react'
    +
    +// https://vitejs.dev/config/
    +export default defineConfig({
    +  plugins: [react()],
    +  resolve: {
    +    alias: {
    +      src: '/src',
    +      components: '/src/components',      
    +    },
    +  },
    +  test: {
    +    globals: true,
    +    setupFiles: ['./setupTests.js'], // es importante definirlo en un archivo aparte para que se ejecute en otro contexto
    +    environment: 'jsdom',
    +    coverage: {
    +      reporter: ['text', 'json', 'html', 'json-summary'],
    +    },
    +  }
    +})
    +
    +    
    +
    +
    + +
    +

    Si no configurás el archivo setupTests.js te va a aparecer un mensaje de error: Error: Invalid Chai property: toBeInTheDocument en cada expect.

    +
    + +

    Por otra parte, los imports conviene hacerlos en forma absoluta, desde src para las definiciones de dominio, services, etc. y src/components para los componentes de React.

    + +

    Archivo jsconfig.json

    + +

    Incorporemos este archivo que nos ayudará para que el plugin auto-import funcione, así como definiciones extra para el intérprete JS:

    + +
    +
    +
    +      
    +        {
    +        
    +  
    +        "compilerOptions"
    +        :
    +         
    +        {
    +        
    +    
    +        "baseUrl"
    +        :
    +         
    +        "."
    +        ,
    +        
    +    
    +        "checkJs"
    +        :
    +         
    +        false
    +        ,
    +        
    +    
    +        "jsx"
    +        :
    +         
    +        "react-jsx"
    +        ,
    +        
    +    
    +        "paths"
    +        :
    +         
    +        {
    +        
    +      
    +        "src/*"
    +        :
    +         
    +        [
    +        
    +        
    +        "./src/*"
    +        
    +      
    +        ],
    +        
    +      
    +        "components/*"
    +        :
    +         
    +        [
    +        
    +        
    +        "./src/components/*"
    +        
    +      
    +        ]
    +        
    +    
    +        }
    +        
    +  
    +        }
    +        
    +
    +        }
    +        
    +
    +      
    +    
    +
    +
    + +

    Nuestra recomendación es que no actives el chequeo de tipos de javascript (para eso es preferible usar typescript). Si lo activás mediante la opción:

    + +
    +
    +
    +          ...
    +    "checkJs": true,
    +    ...
    +
    +    
    +
    +
    + +

    en el archivo jsconfig.json, tenés que agregar esta configuración al archivo vite.config.js:

    + +
    +
    +
    +          coverage: {
    +      // agregar
    +      provider: 'v8',
    +      //
    +      reporter: ['text', 'json', 'html', 'json-summary'],
    +    },
    +
    +    
    +
    +
    + +

    Ejemplo de un archivo para Github Actions

    + +

    Te dejamos este archivo de ejemplo que tenés que guardar en .github/workflows/build.yml. No hay que hacer ningún cambio.

    + +

    Cómo configurar los badges en tu README

    + +
      +
    • +

      Para agregar el badge del build de Github Actions, seguí estas instrucciones

      +
    • +
    • +

      Para agregar el badge del porcentaje de cobertura, tenés que agregar la imagen que genera el mismo build de Github Actions (tal cual está escrito):

      +
    • +
    + +
    +
    +
    +      ![coverage](./badges/coverage/coverage.svg)
    +
    +    
    +
    +
    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/recursividad-en-haskell.html b/wiki/articles/recursividad-en-haskell.html new file mode 100644 index 0000000000..21cfccaa69 --- /dev/null +++ b/wiki/articles/recursividad-en-haskell.html @@ -0,0 +1,409 @@ + + + + + + + + + + + Recursividad en haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Recursividad en haskell +

    +
    + + + +
    +

    Una función recursiva es aquella que en su definición se invoca a sí misma. La misma por lo general cuenta con una definición recursiva y al menos un caso base que corta la recursividad.

    + +

    Recursividad sin listas

    + + + + + + + + +
    Un ejemplo clásico de recursividad es [http://es.wikipedia.org/wiki/Sucesi%C3%B3n_de_FibonacciFibonacci].
    + +
    fibonacci 0 = 0
    +fibonacci 1 = 1
    +fibonacci n = fibonacci (n-1) + fibonacci (n-2)
    +
    + +

    Esta función tiene dos casos base para el 0 y el 1 (ya que la definición recursiva requiere el resultado para los dos números anteriores, no alcanza con un solo caso base) y para todos los otros números una definición recursiva genérica.

    + +

    Es necesario definir primero los casos base, ya que la variable n es un patrón demasiado genérico, tanto el 0 como el 1 matchean con la variable n, por ende deben definirse antes los casos para el 0 y para el 1 para que sean encontrados primero por el motor de Haskell.

    + +

    Para pensar: qué pasa si la consulta realizada es

    + +
    fibonacci (-1)
    +
    + +

    Dado que la tercer definición admite números negativos va a entrar en un loop infinito. Como no es correcto usar fibonacci con números negativos, podríamos mejorar nuestra definición restringiendo el dominio de la función usando guardas de esta forma:

    + +
    fibonacci 0 = 0
    +fibonacci 1 = 1
    +fibonacci n | n >= 2 = fibonacci (n-1) + fibonacci (n-2)
    +
    + +

    Ahora el resultado de aplicar fibonacci con un número negativo sería un error ya que no hay ninguna definición válida para el valor indicado :)

    + +

    Recursividad con listas

    + +

    Siendo las listas estructuras recursivas (compuestas por una cabeza y una cola que a su vez es una lista) la forma más natural para trabajar con ellas es recursivamente. La lista [1,2,3] puede también escribirse como 1:2:3:[] (donde el : es la función usada para armar listas y puede ser usada convenientemente para pattern matching)

    + +

    Un ejemplo fácil es el length.

    + +
    length [] = 0
    +length (x:xs) = 1 + length xs
    +
    + +

    length recursion example

    + +

    Veamos ahora la función reverse.

    + +
    reverse [] = []
    +reverse (x:xs) = reverse xs ++ [x]
    +
    + +

    reverse recursion example

    + +

    Usamos el patrón de lista vacía [] para el caso base, ya que la segunda definición indefectiblemente nos llevará a ella, y el patrón de cabeza y cola para poder avanzar de a un paso por la estructura y poder procesarla fácilmente. En estos casos en particular no importa el orden de las definiciones, ya que la lista con al menos un elemento no matchea con la lista vacía y viceversa.

    + +

    Loops infinitos

    + +

    Analicemos la siguiente función:

    + +
    muchosDe n = n:(muchosDe n)
    +
    + +

    Si consultamos en el intérprete

    + +
    > muchosDe 5
    +
    + +

    Esta función no podría terminar nunca, ya que no hay ningún punto en el que se corte la recursividad. Sin embargo, lo que sí podríamos hacer con esta función es usarla en un contexto que acote la ejecución gracias a la evaluación perezosa. Veamos el siguiente ejemplo:

    + +
    > (sum.take 10.muchosDe) 5
    +50
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/recursividad-en-logico.html b/wiki/articles/recursividad-en-logico.html new file mode 100644 index 0000000000..2b328a5bd0 --- /dev/null +++ b/wiki/articles/recursividad-en-logico.html @@ -0,0 +1,470 @@ + + + + + + + + + + + Recursividad en logico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Recursividad en logico +

    +
    + + + +
    +

    Un predicado recursivo es aquel que en alguna de sus cláusulas se invoca a sí mismo. Los predicados recursivos para poder funcionar correctamente necesitan contar con algún caso base que corte la recursividad.

    + +

    Recursividad Sin Listas

    + +

    Un primer ejemplo es el predicado ancestro/2 que relaciona a una persona con otra si la primera cumple con ser su padre o ser ancestro de su padre. Teniendo un predicado padre(Padre, Hijo) podemos hacer:

    + +
    ancestro(Ancestro, Descendiente):-
    +  padre(Ancestro, Descendiente).
    +  
    +ancestro(Ancestro, Descendiente):-
    +  padre(Padre, Descendiente),
    +  ancestro(Ancestro, Padre).
    +
    + +

    Acá se ve que ancestro/2 tiene dos cláusulas: una que se invoca al mismo predicado ancestro/2 y otra que no. No importa cuál de las dos definamos primero, porque Prolog va a intentar ambas de todos modos. Lo que sí es importante de la cláusula recursiva es que demos un pasito que nos acerque al caso base antes de hacer la consulta recursiva, en este caso es preguntar quién es ancestro del padre de la persona que nos interesaba en primer lugar.

    + +

    Algo que puede parecer complejo es analizar la inversibilidad de este predicado. Teniendo en cuenta que el predicado padre/2 es inversible, el caso base es inversible, pero ¿qué pasa con el caso recursivo? Las variable Descendiente se va a ligar gracias a padre/2, y la variable Ancestro aparece por primera vez al consultar el mismo predicado que estamos definiendo… Bueno, gracias a que el caso base es inversible, podemos confiar que eventualmente se va a ligar, por ende ancestro/2 se hace inversible a sí mismo.

    + +

    Una cosa interesante para pensar en este ejemplo es que el predicado ancestro/2 define una relación que cumple con la propiedad transitiva. Recordando un poco la teoría detrás de esto: “Una relación R es transitiva si: a R b y b R c => se cumple a R c”.

    + +

    Otro ejemplo típico de predicado recursivo es factorial/2, que relaciona a un número con su factorial sabiendo que para el 0 es 1 y para los otros números es el factorial del número anterior multiplicado por sí mismo. Una primer aproximación en base a esto podría ser:

    + +
    factorial(0,1).
    +factorial(N,F):- 
    +  Anterior is N-1,
    +  factorial(Anterior,F2),
    +  F is F2*N.
    +
    + +

    Esta definición parece que resuelve el problema, pero no hay que olvidarse que en el paradigma lógico la búsqueda de soluciones es exhaustiva. Si consultamos por el factorial de 1, la primer respuesta será 1 ya que el factorial de 0 es 1, y 1 * 1 da 1. Pero siendo que 0 también matchea con la variable N entrará en un loop infinito al segundo intento. Por ese motivo, una definición correcta sería:

    + +
    factorial(0,1).
    +factorial(N,F):- N > 0,
    + Anterior is N-1,
    + factorial(Anterior,F2),
    + F is F2*N.
    +
    + +

    De esa forma, ambos casos son excluyentes entre sí y el 0 sólo puede tener como respuesta al 1.

    + +

    ¿Y la inversibilidad? Algo que salta a la vista es que para consultar el factorial del anterior necesitamos calcular el anterior, y también necesitamos validar que N > 0, y eso impone restricciones porque los predicados (>)/2 e is/2 necesitan que N esté ligada con un valor concreto. O sea que esta consulta no va a funcionar: factorial(N, 6).

    + +

    Analicemos la inversibilidad para la segunda aridad. Esta otra consulta: factorial(3, Factorial). ¿funcionaría?

    + +

    La variable F aparece recién al final, a la izquierda del is, con lo cual no habría problema por ese lado.

    + +

    De hecho, si no fuera inversible para la segunda aridad la consulta recursiva no se podría resolver tampoco, porque se está usando una variable F2 que no tiene chances de estar ligada previamente como para que sea una consulta individual. Al igual que para el primer ejemplo, esa consulta recursiva funciona gracias a que tiende al caso base que es inversible.

    + +

    Recursividad Con Listas

    + +

    Las listas son indiviuos compuestos cuya naturaleza es recursiva, por ese motivo la recursividad es una forma común para trabajar con ellas. La clave para hacer un ejercicio, si éste se resuelve con recursividad, es poder pensar recursivamente. Ésto significa que cuando digan, por ejemplo “una sumatoria se define como…..” ahí, en la definición, tienen que usar el concepto de sumatoria de nuevo, para definirla. ¿Cómo? Y, separando el problema, por ejemplo, en cabeza y cola. Y ese es el chiste, juntando esas dos cosas y pensando un poquito, pueden hacer recursividad sobre listas.

    + +

    Sumatoria

    + +

    La cola de una sumatoria ¿qué tiene que ver con la sumatoria de la lista entera? Y, la sumatoria de la cola es casi todo el problema resuelto, sólo le falta agregar un detallito que implica trabajar con el elemento que tenemos disponible:

    +
    sumatoria([Cabeza|Cola], S):-
    +       sumatoria(Cola,SCola), % Esto ya es casi todo el problema resuelto! Solo falta sumar la cabeza:
    +       S is SCola + Cabeza.
    +
    + +

    Y por supuesto que necesitamos un caso base. El caso base se piensa generalmente por exclusión…. ¿Qué caso no consideré arriba? La lista vacía. (En éste caso)

    + +

    sumatoria([],0).

    + +

    Ultimo

    + +

    A ver, el último de una lista… ¡Es el mismo último de la cola!:

    + +
    ultimo([Cabeza|Cola],Ultimo):-
    +          ultimo(Cola,Ultimo).
    +
    + +

    Caso base, una lista con un elemento (la lista vacía no tiene último, sería esperable que una consulta para la lista vacía de falso):

    + +

    ultimo([E],E).

    + +

    Completito:

    + +
    ultimo([_|Cola],Ultimo):-
    +          ultimo(Cola,Ultimo).
    +ultimo([E],E).
    +
    + +

    Todos menos el último

    + +

    Ahora, el principio de la lista (todos menos el último). Éste es loquito, porque podemos partir ambas listas, así:

    + +

    principio([Cabeza|Cola],[Cabeza|PrincipioDeLaCola]):-

    + +

    Y claro, porque la cabeza es la misma en la lista original que en su principio. Pero hay que relacionar Cola y PrincipioDeLaCola…..

    +
    principio([Cabeza|Cola],[Cabeza|PrincipioDeLaCola]):- 
    +        principio(Cola,PrincipioDeLaCola).
    +principio([E],[]).
    +
    + +

    Reverse

    + +

    Entonces, pensemos otro problema: dar vuelta una lista. Es un poco más interesante: Necesitamos poner el último adelante, y la cola de la lista dada vuelta es el principio de la lista al revés:

    + +

    reverse(ListaOriginal,[Ultimo|PrincipioAlReves]):-

    + +

    Uf, pero hay que ver de dónde sale eso! Y, la llamada recursiva la conocemos:

    + +

    reverse(PrincipioDeLaLista,PrincipioAlReves),

    + +

    Y listo, ahora hay que poner antes y después de esa condición cosas para que ligue las variables correspondientes; Ligamos PrincipioDeLaLista, antes de la llamada recursiva:

    +
    reverse(ListaOriginal,[Ultimo|PrincipioAlReves]):-
    +            principio(ListaOriginal,PrincipioDeLaLista),
    +            reverse(PrincipioDeLaLista,PrincipioAlReves), ...
    +
    + +

    Y ahora nos falta saber de dónde sacamos el último:

    +
    reverse(ListaOriginal,[Ultimo|PrincipioAlReves]):-
    +            principio(ListaOriginal,PrincipioDeLaLista),
    +            reverse(PrincipioDeLaLista,PrincipioAlReves),
    +            ultimo(ListaOriginal,Ultimo).
    +
    +

    Les dejo el caso base a ustedes.

    + +

    Ejercicio: Subconjunto

    + +

    ¿Cómo se hace el subconjunto de una lista? (sin permutaciones)

    + +

    Así tiene que funcionar:

    +
    `?- subconjunto([1,2,3],Sub).`
    +Sub = [];
    +Sub = [2];
    +Sub = [2,3];
    +Sub = [3];
    +Sub = [1];
    +Sub = [1,2];
    +Sub = [1,2,3];
    +Sub = [1,3];
    +false.
    +
    +

    Pista: El subconjunto puede pensarse con dos casos recursivos más el caso base.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/redefinicion.html b/wiki/articles/redefinicion.html new file mode 100644 index 0000000000..8631b401c8 --- /dev/null +++ b/wiki/articles/redefinicion.html @@ -0,0 +1,317 @@ + + + + + + + + + + + Redefinicion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Redefinicion +

    +
    + + + +
    +

    La redefinición se produce cuando una clase vuelve a definir, o sea redefine, alguno de los métodos heredados de su superclase. El nuevo método sustituye al heredado para todos los objetos de la clase que lo ha redefinido, de manera que sus objetos tienen un comportamiento modificado respecto de los objetos de la superclase.

    + +

    Así, la redefinición permite que al definir una nueva clase sus objetos no sólo extiendan o amplíen el funcionamiento de los objetos de la superclase, sino también los modifiquen, ajustándolo a los requerimientos y necesidades específicas para los cuales se creó la subclase.

    + +

    La redifinición se puede usar para definir la misma operación que antes pero con alguna variante (acá mayormente se usa super) o para definir la misma operación sin código en común con el heredado (es una redefinición sin super, se puede ver un ejemplo en Prototipado vs Clases#Redefinir comportamiento).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/refactoring.html b/wiki/articles/refactoring.html new file mode 100644 index 0000000000..767cc119a4 --- /dev/null +++ b/wiki/articles/refactoring.html @@ -0,0 +1,339 @@ + + + + + + + + + + + Refactoring + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Refactoring +

    +
    + + + +
    +

    This article is a stub!

    + + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/reflection.html b/wiki/articles/reflection.html new file mode 100644 index 0000000000..faa4f19eab --- /dev/null +++ b/wiki/articles/reflection.html @@ -0,0 +1,433 @@ + + + + + + + + + + + Reflection + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Reflection +

    +
    + + + +
    +

    Es un caso particular de metaprogramación, donde “metaprogramamos” en el mismo lenguaje en que están escritos (o vamos a escribir) los programas. Es decir, todo desde el mismo lenguaje.

    + +

    Nota de color: Inicialmente el lenguaje “pionero” en cuanto a reflection fue LISP.

    + +

    El ejemplo más visible de esto es el caso de smalltalk, donde no existe una diferenciación entre IDE y nuestro programa. Ambos estan hechos en smalltalk, y de hecho viven en un mismo ambiente. Ambos estan construidos con objetos y pueden interactuar entre sí.

    + +

    De hecho, muchos componentes del “IDE” Pharo son elementos de metaprogramación, y utilizan reflection para inspeccionar nuestras clases y objetos.

    + +

    Tipos de reflection

    + +

    Para esto, generalmente, es necesario contar con facilidades o herramientas específicas, digamos “soporte” del lenguaje. Entonces reflection, además, abarca los siguientes items que vamos a mencionar en esta lista:

    + +
      +
    • Introspection: se refiere a la capacidad de un sistema, de analizarse a sí mismo. Algo así como la introspección humana, pero en términos de programa. Para eso, el lenguaje debe proveer ciertas herramientas, que le permitan al mismo programa, “ver” o “reflejar” cada uno de sus componentes.
    • +
    • Self-Modification: es la capacidad de un programa de modificarse a sí mismo. Nuevamente esto requiere cierto soporte del lenguaje. Y las limitaciones van a depender de este soporte.
    • +
    • Intercession: es la capacidad de modificar la semántica del modelo que estamos manipulando, desde el mismo lenguaje.
    • +
    + +

    Un MOP (MetaObject Protocol) es un framework de objetos que describe o modela un sistema de objetos. MOP sería el término correcto para lo que en java llamamos API de reflection. En realidad el API de reflection de java es un caso de MOP.

    + +

    Dependiendo de la implementación y del lenguaje, el MOP puede soportar o no los tipos de reflection que enumeramos arriba: introspection, self-modification & intercession.

    + +

    Introspection

    + +

    Se refiere a poder obtener información acerca de los elementos de nuestro programa: clases, fields, métodos, funciones, predicados (en otros paradigmas).

    + +

    La capacidad de introspection es la más común en los MOP’s. Digamos que es la más “simple” de implementar, comparándolas con los otros tipos de reflection.

    + +

    Veamos algunas herramientas que nos dan los lenguajes Java y Smalltalk (Pharo):

    + +

    Información estática:

    + +

    Para obtener la clase de un objeto: +   en Java: getClass +   en Pharo: class +    +En la clase class están los métodos: +   en Java: getMethods, getDeclaredMethods, getFields, getConstructors, getMethod, getSuperclass +   en Pharo: instVariables, methodDictionary, superclass

    + +

    Información dinámica:

    + +

    Obtener el valor de un field: +   en Java: unField.get(unObjeto) +   en Pharo: unObjeto instVarNamed: fieldName +Setear el valor de un field: +   en Java: unField.set(unObjeto, unValor) +   en Pharo: unObjeto instVarNamed: fieldName put: unValor +Invocar un método: +   en Java: unMethod.invoke(unObjeto, parametro1, parametro2, ...) +   en Pharo: unObjeto perform: #selector withArguments: listaDeParametros +Crear una instancia: +   en Java: unConstructor.invoke(parametro1, parametro2, ...) o unaClase.newInstance() +   en Pharo: unaClase new    

    + +

    Self-modification

    + +

    Supongamos que queremos hacer el refactor extract superclass, para esto vamos a usar self-modification en Pharo, donde modificar el metamodelo usando el mismo lenguaje es algo cotidiano por ejemplo, para crear una clase usamos el template que nos provee el System Browser:

    + +

     Object subclass: #NameOfSubclass +   instanceVariableNames: '' +   classVariableNames: '' +   poolDictionaries: '' +   category: ''.

    + +

    que no es más que un mensaje que se le manda a la clase Object.

    + +

    Lo que hacemos es, dada una clase, crear una super clase a partir de ella, diciéndole el nombre de le nueva clase, las variables de instancia que quiero que tenga, los métodos que quiero que tenga. Así es como nos gustaría poder usarlo:

    + +

    SimpleExtractSuperclassRefactoring  +  extractSuperclass: #Guerrero +  withInstanceVariables: Soldado instVarNames +  andMethods: (Soldado selectors difference: #(paso fuerza)) +  fromClass: Soldado.

    + +

    El resultado de esta prueba debería ser crear una clase Guerrero, a partir de otra clase Soldado ya existente. Guerrero va a ser superclase de Soldado y va a tener todas las variables de instancia que tiene Soldado (le podríamos especificar cuáles variables de instancia queremos ponerle, pero por simplicidad, le pasamos todas). También vamos a mover todos los métodos de Soldado, excepto paso y fuerza.

    + +

    Por supuesto, nuestro refactor debe ser independiente del dominio de los guerreros. Nuestro metaprograma sería básicamente (obviando accessors):

    + +

    #SimpleExtractSuperclassRefactoring class +>> extractSuperclass: newSuperClassName withInstanceVariables: instanceVariableNames andMethods: selectorsToMove fromClass: aClass + self new +   target: aClass; +   superClassName: newSuperClassName; +   instanceVariableNames: instanceVariableNames; +   selectors: selectorsToMove;  +   execute.

    + +

    #SimpleExtractSuperclassRefactoring +>> execute +  self createSuperClass. +  self moveInstanceVariables. +  self moveMethods.

    + +

    >> createSuperClass +  self targetSuperClass: (self target superclass +                                     subclass: self superClassName +                                     instanceVariableNames: '' +                                     classVariableNames: '' +                                     poolDictionaries: '' +                                     category: self target category). +  self targetSuperClass subclass: self target name +                        instanceVariableNames: self target instanceVariablesString +                        classVariableNames: self target classVariablesString +                        poolDictionaries: '' "Ahora no nos importa, pero habría que copiarlo también para que no se pierda" +                        category: self target category.

    + +

    >> moveInstanceVariables +  self instanceVariableNames do: [:instVarName | +    self target removeInstVarNamed: instVarName. +    self targetSuperClass addInstVarNamed: instVarName. ]

    + +

    >> moveMethods +  self selectors do: [:selector | +    self targetSuperClass compile: (self target >> selector) getSource. +    self target removeSelector: selector. ] + 

    + +

    Algunos métodos de self-modification que usamos:

    + +
      +
    • Agregar un método: unaClase compile: ‘…código del método’
    • +
    • Borrar un método: unaClase removeSelector: #selector
    • +
    • Agregar una variable de instancia: unaClase addInstVarNamed: ‘nombre de la variable’
    • +
    • y para borrarla: unaClase removeInstVarNamed: ‘nombre de la variable’
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/relleno-caprese.html b/wiki/articles/relleno-caprese.html new file mode 100644 index 0000000000..27bc22e23e --- /dev/null +++ b/wiki/articles/relleno-caprese.html @@ -0,0 +1,318 @@ + + + + + + + + + + + Relleno caprese + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Relleno caprese +

    +
    + + + +
    +

    Cantidad: 1 docena y media

    + +

    Ingredientes:

    + +
      +
    • 150 gramos de Jamon
    • +
    • 235 gramos de Muzzarella (el paquete de La Serenisima)
    • +
    • Medio paquete de Albahaca
    • +
    • Un tomate bien grande.
    • +
    • Sólo un poquito de sal al tomate + albahaca
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/relleno-dale.html b/wiki/articles/relleno-dale.html new file mode 100644 index 0000000000..23b9da53e1 --- /dev/null +++ b/wiki/articles/relleno-dale.html @@ -0,0 +1,313 @@ + + + + + + + + + + + Relleno dale + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Relleno dale +

    +
    + + + +
    +

    Cantidad: 1 docena y media

    + +

    Ingredientes:

    + +
      +
    • 125 gramos de jamon
    • +
    • 235 gramos de queso, 80% fontina y un toque de Muzzarella
    • +
    • 3 cebollas chicas
    • +
    • 1 cebolla de verdeo.
    • +
    • 1 morrón (medio verde y medio rojo)
    • +
    • un puñado de aceitunas, ponele 8 a 10.
    • +
    • 2 huevos duros
    • +
    • Condimentos, un caldito de verdura, aceite, sal, pimienta y condimento para pizza, todo en el preparado de cebolla + morrón.
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/relleno-de-carne.html b/wiki/articles/relleno-de-carne.html new file mode 100644 index 0000000000..6a6f2897be --- /dev/null +++ b/wiki/articles/relleno-de-carne.html @@ -0,0 +1,320 @@ + + + + + + + + + + + Relleno de carne + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Relleno de carne +

    +
    + + + +
    +

    Cantidad: 2 docenas y media

    + +

    Ingredientes:

    + +
      +
    • 1kg de carne
    • +
    • 1kg de cebollas
    • +
    • 4 huevos duro
    • +
    • 2 cebolla de verdeo
    • +
    • 1 morrón rojo
    • +
    • 1 morrón verde
    • +
    • Un poquito de salsa de tomate
    • +
    • Comino
    • +
    + +

    Extras:

    + +
      +
    • Aceitunas, 10
    • +
    • Medio Chorizo
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/representacion-de-informacion.html b/wiki/articles/representacion-de-informacion.html new file mode 100644 index 0000000000..2c98bc3e91 --- /dev/null +++ b/wiki/articles/representacion-de-informacion.html @@ -0,0 +1,302 @@ + + + + + + + + + + + Representacion de informacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Representacion de informacion +

    +
    + + + +
    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/resolver-problemas-de-dependencias-maven-dentro-de-eclipse.html b/wiki/articles/resolver-problemas-de-dependencias-maven-dentro-de-eclipse.html new file mode 100644 index 0000000000..80bfad826e --- /dev/null +++ b/wiki/articles/resolver-problemas-de-dependencias-maven-dentro-de-eclipse.html @@ -0,0 +1,349 @@ + + + + + + + + + + + Resolver problemas de dependencias maven dentro de eclipse + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Resolver problemas de dependencias maven dentro de eclipse +

    +
    + + + +
    +

    Cuando el plugin de maven dentro de eclipse no puede resolver una dependencia puede ser por varios motivos, aquí tratamos de armar una lista de cosas para revisar.

    + +

    Está mal el settings.xml

    + +

    Normalmente si estuviera mal el settings entonces debería quejarse por no encontrar el parent project y no esos, pero si no le pusiste parent a tu pom entonces podría mostrar ese error. Por otro lado si tenés algún otro ejemplo de la cátedra que te anda, eso querría decir que el settings está bien.

    + +

    Dentro del eclipse se configura donde está el settings.xml en Windows / Preferences -> Maven / User Settings. En principio ese debería ser el settings.xml que hay que modificar para agregarle el repo maven de uqbar.

    + +

    Está mal el pom.xml

    + +

    Si tenés mal las versiones no te va a andar. Asegurate de copiar exactamente lo que dice algún pom de ejemplo.

    + +

    Está mal nuestro server… creo que no es el caso, pero nunca hay que descartar esa opción.

    + +

    Está mal la conexión a Internet.

    + +

    Asegurate de tener Internet y que el maven/eclipse tengan acceso a ella, revisar firewalls, proxies etc.

    + +

    Está mal tu repo local

    + +

    Esto es más probable de lo que podría pensarse, si todo lo anterior falla lo más lógico es que sea esto. Suele pasar cuando uno usa maven desde una conexión mala (como la de frba), intenta bajar un jar, no lo logra y se mambea: queda registrado como que no se pudo bajar y no vuelve a intentar.

    + +

    Para resolver esto hay que ir al repo local y borrar la info de cache… una forma fácil es borrar todo el directorio “uqbar”, pero si miran a dentro pueden ser más sutiles.

    + +

    Está mal el eclipse

    + +

    El eclipse también tiene sus cachés y no es raro que se mambeen… acá no hay soluciones elegantes, darle clean al proyecto, clean al maven, restartearl el eclipse… y todas esas cosas desagradables.

    + +

    En algún caso yo lo resolví haciendo un touch del archivo .classpath

    + +

    Borrar parte del repo local también obliga al eclipse a refrescar sus cachés.

    + +

    Mi proyecto no es de tipo maven / No tengo el menú maven en mi proyecto

    + +

    Visualmente se puede ver si un proyecto es de tipo maven en el ícono del proyecto. Este debería tener una “m” en el mismo.

    + +

    Para convertirlo a proyecto maven hay que apretar click derecho sobre el proyecto y luego Configure / Convert to Maven Project

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/responsiveness.html b/wiki/articles/responsiveness.html new file mode 100644 index 0000000000..789932e3c4 --- /dev/null +++ b/wiki/articles/responsiveness.html @@ -0,0 +1,396 @@ + + + + + + + + + + + Responsiveness + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Responsiveness +

    +
    + + + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Aplicaciones responsive

    + +

    + responsiveness +

    + +

    Hacer que una aplicación sea responsive implica optimizar el contenido y la interacción de la interfaz de usuario en base al tamaño y resolución de la pantalla.

    + +

    Esto se relaciona con el concepto de usabilidad: el contenido debe adaptarse para pantallas más chicas (celulares, en modo vertical o apaisado), medianas (tablets) o grandes (monitores de 25”), a veces implica reordenar los controles, a veces sacar los elementos que pueden llegar a molestar la experiencia de usuario.

    + +

    Algunos frameworks de presentación web que trabajan sobre esta idea son:

    + + + +

    entre otros.

    + +

    Manualmente, el css permite especificar estilos condicionales mediante el uso de media queries. Podés ver un ejemplo que discrimina css para desktops, tablets, teléfonos grandes y pequeños.

    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/resumen-de-wicket--pros-y-contras.html b/wiki/articles/resumen-de-wicket--pros-y-contras.html new file mode 100644 index 0000000000..295bbe7b21 --- /dev/null +++ b/wiki/articles/resumen-de-wicket--pros-y-contras.html @@ -0,0 +1,432 @@ + + + + + + + + + + + Resumen de wicket pros y contras + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Resumen de wicket pros y contras +

    +
    + + + +
    +

    Resumen general

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TemaCómo lo resuelve Wicket
    WidgetsSi bien dependen de lo que HTML ofrece, del lado del servidor se puede trabajar con componentes visuales que rendericen tablas paginadas, combos anidados, etc.
    LayoutAl igual que en Web, el layout no está reificado en objetos del lado del servidor sino que se define en el html (y opcionalmente en el css).
    BindingSe mapea cada componente con su modelo correspondiente (estático o dinámico). El CompoundPropertyModel trabaja por convención y permite bajar la cantidad de líneas de configuración.
    Manejo de estadoLa página tiene estado como cualquier objeto que pertenece al ambiente Java.
    NavegaciónSe pueden generar nuevas instancias de una página o recibir una página como parámetro. Al abrir nuevas sesiones desde el browser se generan nuevas instancias de página automáticamente. La navegación es a nivel aplicación y no a nivel hipervínculo de documento.
    Pasaje de información entre páginasPuedo definir constructores para las páginas, pasando como parámetro toda la información que necesite (incluyendo la página padre).
    Manejo de eventosLos botones deben definirse como submit y no como button para que pueda funcionar el binding de atributos, por las restricciones de la tecnología web: sólo con submit los parámetros viajan al servidor. Los buttons como los links definen sus listeners, el mapeo es sencillo: no hay que escribir tres servlets distintos para comprar, reservar o dar de baja la reserva, ni escribir un servlet que en el doGet/doPost tenga un switch gigante.
    + +

    Highligths

    + +
      +
    • Stateful Model +
        +
      • manejo automático de estado en sesión
      • +
      • no requiere conocer scopes: session, request, etc.
      • +
      +
    • +
    • Modelo de componentes al estilo SWT +
        +
      • soporta extensiones trabajando con técnicas OO conocidas
      • +
      +
    • +
    • Transparencia en la comunicación con el server +
        +
      • Al igual que en cliente pesado, los métodos “onClick()” son invocados automáticamente por el framework
      • +
      +
    • +
    • Html markup muy poco intrusivo +
        +
      • Sólo hay que anotar el tag con el id del componente. Ej: Aceptar
      • +
      • Al trabajar con un html de prueba, eso permite la separación de tareas entre el diseñador y el programador (el diseñador no sufre si hay problemas de performance o cambio en los datos porque el html contiene un prototipo de ejemplo en sí mismo)
      • +
      +
    • +
    + +

    Problemas

    + +
      +
    • Sigue atado al concepto de formulario +
        +
      • Si bien el form es un objeto con las ventajas que eso trae,
      • +
      • el desarrollador tiene que pensar en el submiteo del form.
      • +
      +
    • +
    • Muy fuerte vínculo entre markup y modelo componentes java. +
        +
      • Hace rígida y burocrática la vista.
      • +
      +
    • +
    • Modelo de componentes orientado a la jerarquía +
        +
      • Hay que subclasear ¡TODO! (botones, links, etc.)
      • +
      • Trabaja poco con composición
      • +
      • Una vez que el programador se hizo amigo de la tecnología, se imponen refactors para evitar escribir muchas líneas de código (que tiende a ser repetitivo, podría mejorarse la interfaz de creación de controles del lado del servidor)
      • +
      +
    • +
    • El uso de Model’s (la M del MVC) es algo oscuro +
        +
      • no muy intuitivo
      • +
      • no fomenta su uso por estas mismas complicaciones.
      • +
      +
    • +
    • No parece ser posible autogenerar la vista (html) automáticamente (al menos en forma fácil). Por ejemplo para una aplicación/producto grande, donde se necesite desarrollar muchas pantallas de carga.
    • +
    + + + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/resumen-lenguajes-prototipados.html b/wiki/articles/resumen-lenguajes-prototipados.html new file mode 100644 index 0000000000..c33155b4c3 --- /dev/null +++ b/wiki/articles/resumen-lenguajes-prototipados.html @@ -0,0 +1,511 @@ + + + + + + + + + + + Resumen de lenguajes basados en prototipos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Resumen de lenguajes basados en prototipos +

    +
    + + + + + +
    +
    +

    Advertencia: esto puede ser un poco fumado.

    +
    + +

    Hemos trabajado hasta aquí la noción de objeto como la primera forma de definir conceptos, agrupar comportamiento y encapsular estado. +Al objeto le puedo enviar un mensaje y el method lookup se resuelve porque el objeto receptor es el que responde al mensaje.

    + +

    Esta forma de definir código en base a un objeto no es exclusiva de Wollok:

    + +

    Self

    + +

    La primera idea de tener la noción de objeto fue Self en 1986, que nació en Xerox Parc Place como hermano menor de Smalltalk (comparten una sintaxis muy similar).

    + +

    Cada objeto define

    + +
      +
    • slots o referencias
    • +
    • métodos
    • +
    + +

    self

    + +

    Fue también el primero que introdujo la idea de manipulación enteramente visual de objetos:

    + +

    morphic

    + +

    Te dejamos dos videos que muestran

    + + + +

    Javascript

    + +

    Un tiempo más tarde nació Javascript (el 01/01/1997), que popularizó el término prototype-based para los lenguajes que trabajan exclusivamente con objetos (al menos hasta la versión ES6 que incorporó las clases como syntatic sugar). Vamos a hacer el ejemplo de pepita en javascript, que pueden probar en la consola de cualquier navegador (presionando F12)

    + +
    // pepita es un objeto...
    +var pepita = {
    +
    +  energia: 0,   // que tiene energia
    +
    +  volar: function(kilometros) {  // que sabe volar n kilómetros (function es equivalente al method de Wollok)
    +    this.energia = this.energia - (8 * kilometros)   // y eso le resta energia (this es equivalente al self de Wollok)
    +  },
    +
    +  comer: function(gramos) {      // que sabe comer g gramos
    +    this.energia = this.energia + (4 * gramos)	
    +  },
    +
    +  cantar: function() {	// que sabe cantar
    +    console.log("pri pri pri")
    +  }
    +}
    +
    + +

    Lo probamos en la consola del navegador

    + +
    // copiamos la definición anterior de pepita
    +pepita
    +pepita.energia   // puedo acceder a información de pepita
    +pepita.comer(50)
    +pepita
    +pepita.volar(10)
    +pepita.energia = 170  // incluso puedo asignar información de pepita sin mandar mensajes
    +pepita.descansar = function() { this.energia = 1000 }  // groso! Puedo definir comportamiento nuevo
    +// incluso puedo crear referencias nuevas
    +pepita.durmioSiesta = false
    +// pisamos la definición
    +pepita.descansar = function() {
    +  this.durmioSiesta = true
    +  this.energia = 1000
    +}
    +// y vemos qué pasa
    +pepita.durmioSiesta
    +pepita.descansar()
    +pepita.durmioSiesta
    +
    + +

    Similitudes con Wollok:

    + +
      +
    • no estoy obligado a definir los tipos. Yo puedo enviar cualquier mensaje que un objeto entienda (así funciona el method lookup básico).
    • +
    • puedo definir objetos anónimos y referenciarlos mediante variables
    • +
    • el objeto agrupa comportamiento y estado (el conjunto de variables)
    • +
    + +

    Algunas diferencias respecto a Wollok

    + +
      +
    • javascript permite el acceso directo a las referencias de un objeto. Wollok nos obliga a hacerlo mediante accessors, para javacript tanto las variables como los métodos son cajoneras donde la única diferencia es que en las segundas guardamos expresiones lambda.
    • +
    • javascript es dinámico: puedo agregar o modificar referencias y comportamiento sin que haya un “reinicio”. En esto reside su gran poder.
    • +
    + +

    En Wollok es necesario cambiar la referencia a un nuevo objeto para poder lograr que un mensaje pueda ser entendido:

    + +
    >>> var pepita = object { }
    +an Object[]
    +>>> pepita.jugar()
    +wollok.lang.MessageNotUnderstoodException: anonymousObject does not understand message jugar()
    +
    +>>> pepita = object { method jugar() { } }
    +an Object[]
    +>>> pepita.jugar()
    +>>>
    +
    + +

    Si quieren chusmear más pueden profundizar sobre

    + + + +

    Ioke

    + +

    Ioke (06/11/2008) fue un proyecto basado en la VM de Java que proponía trabajar con prototipos, intercalando lenguajes como Io, Ruby y Lisp. Vemos la misma implementación de pepita en Ioke:

    + +
    pepita = Origin mimic do(
    +  energia = 0.0
    +  comer = method(gramos, self energia += 4 * gramos)
    +  volar = method(kilometros, self energia -= (kilometros + 10))
    +  show = method("Pepita energia: $#{energia}" println)
    +)
    +
    +pepita show
    +"Pepita come 10 gramos" println
    +pepita comer(10)
    +"Pepita vuela 3 kilometros" println
    +pepita volar(3)
    +pepita show
    +
    + +

    El archivo pepita.ik tiene la definición de pepita y luego el script que prueba cómo come y vuela.

    + +

    Lo evaluamos en la consola

    + +
    fernando@fernando-laptop ~/apps/ioke/bin $ ./ioke pepita  .ik
    +Pepita energia: $0.0
    +Pepita come 10 gramos
    +Pepita vuela 3 kilometros
    +Pepita energia: $27.0
    +
    + +

    Ozono

    + +

    Ozono (anteriormente llamado LOOP: Learning Object-Oriented Programming) fue una herramienta desarrollada por algunos docentes de esta facultad que permitía el trabajo con objetos antes de utilizar otras herramientas de Smalltalk.

    + +

    Otras apariciones de object

    + +

    En Scala aparece la noción de objeto pero asociada al Singleton.

    + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/robustez-de-los-lenguajes.html b/wiki/articles/robustez-de-los-lenguajes.html new file mode 100644 index 0000000000..f82a2f5b1d --- /dev/null +++ b/wiki/articles/robustez-de-los-lenguajes.html @@ -0,0 +1,351 @@ + + + + + + + + + + + Robustez de los lenguajes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Robustez de los lenguajes +

    +
    + + + +
    +

    Se dijo:

    + +
    +

     ”No implementaría el software de una central atómica en Ruby”

    +
    + +

    Y eso disparó una discusión acerca de qué hace que un lenguaje de programación, una práctica, o una herramienta sea segura para un software que no puede fallar, que debería tener la menor cantidad de errores posibles y ser tolerante a ellos en caso que ocurran.

    + +

    Se llegó a los siguientes vínculos de la United States Nuclear Regulatory Commission (NRC):

    + + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ruby.html b/wiki/articles/ruby.html new file mode 100644 index 0000000000..7b2ba3ea3b --- /dev/null +++ b/wiki/articles/ruby.html @@ -0,0 +1,358 @@ + + + + + + + + + + + Ruby + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Ruby +

    +
    + + + +
    +

    No es este Ruby, pero les dejamos otros links interesantes:

    + +

    Sobre el lenguaje:

    + + + +

    Herramientas basadas en Ruby:

    + + + +

    La comunidad:

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/sabores-de-colecciones.html b/wiki/articles/sabores-de-colecciones.html new file mode 100644 index 0000000000..0b0351897f --- /dev/null +++ b/wiki/articles/sabores-de-colecciones.html @@ -0,0 +1,455 @@ + + + + + + + + + + + Sabores de colecciones + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Sabores de colecciones +

    +
    + + + +
    +

    Sabores de colecciones en Wollok

    + +

    En Wollok disponemos de dos sabores básicos de colecciones: las listas y los sets (conjunto matemático). Se diferencian principalmente por las siguientes características:

    + +
      +
    • Las listas tienen orden, los sets no, por eso sólo es posible obtener un determinado elemento en base a su pocisión sólo si es una lista con el mensaje get(posicionBaseCero)
    • +
    • Los sets no admiten repetidos, las listas sí, por eso si se agrega un elemento repetido a un set no se agregará una nueva referencia al mismo, mientras que en las listas se incluirá una nueva referencia (en otra posición) al mismo objeto.
    • +
    + +

    Literal de listas: [1,2,3] Literal de sets: #{1,2,3}

    + +

    Para ejemplos de uso ver Intro a colecciones

    + +

    Sabores de colecciones en Smalltalk

    + +

    Smalltalk tiene una clase llamada Collection que me permite representar colecciones, pero Collection es la abstracción superior de la jerarquía de colecciones. Al momento de instanciar una colección, tengo que decidirme por un sabor. A continuación intentaremos mostrar los sabores de colecciones, tratando de ordenarlos en base a sus respectivos grados de especialización.

    + +

    Set y Bag

    + +

    El primer sabor que visitaremos es el Bag. Esta colección es de las denominadas sin orden y como su nombre lo indica, es la representación de una bolsa. Una bolsa de objetos. Por ejemplo, al principio, hablamos de un carrito de compras. El Bag la colección más adecuada para esta representación. Imagínense que puedo poner tres latas de tomates, dos botellas de agua y siete peras.

    + +

    El segundo sabor que veremos es el Set. El Set, como su nombre lo indica, está concebido para la representación de conjuntos.

    + +

    Una propiedad, fundamental diría, sobre conjuntos es que los elementos que pertenecen al conjunto son únicos en él. En resumidas palabras, en los conjuntos (Sets) no voy a tener dos veces el mismo elemento. O sea el Set no admite repetidos. Salvo por esta propiedad, el comportamiento es el mismo que el del Bag.

    + +

    Imagínense que tengo una lata de tomates y miCarrito es una colección. Lo voy a representar así:

    + +

    unaLata := LataDeTomates new.  +unaLata conTomates: ‘perita’.  +unaLata deLaMarca: ‘La Marca que a uds les guste’  +unaLata conPrecio: 1.00 

    + +

    Bien, tengo mi objeto unaLata y quiero agregar a mi carrito de compras 3 latas de tomates. Entonces hago:

    + +

    miCarrito add: unaLata.  +miCarrito add: unaLata.  +miCarrito add: unaLata. 

    + +

    ¿Qué pasará cuando evalúe la siguiente línea?

    + +

    miCarrito size.

    + +

    Yo agregué 3 veces al carrito una lata de tomates, con lo cual podría esperar que me responda 3. Pero, como vimos, si represento a mi carrito de compras con un Bag, (o sea que hice miCarrito:= Bag new.) entonces sí voy a tener 3 referencias a unaLata en miCarrito.

    + +

    Si representara mi carrito de compras con un Set (o sea que hice miCarrito:=Set new.) entonces hubiese tenido un solo objeto dentro de mi colección. Simplemente, cuando hago el segundo miCarrito add: unaLata el Set identifica que ya tiene ese objeto en la colección y no lo vuelve a agregar.

    + +

    Colecciones ordenadas

    + +

    Entonces ya vimos el Set y Bag, que son colecciones sin orden. Ahora introduciremos algunas colecciones con orden.

    + +

    ¿Qué quiere decir ordenadas? Que hay un elemento 1, un elemento 2, etc., al contrario de un Set o un Bag, en donde los elementos están “todos tirados”. O sea, puedo acceder a los elementos de cualquier colección ordenada (veremos que hay varias variantes) parecido a como se accede a un Array en C o Pascal. Para eso le envío a la colección el mensaje at: , si quiero el cuarto elemento de miCol que es una colección ordenada, lo puedo pedir así:

    + +

    miCol at: 4 

    + +

    y tengo los mensajes first y last que devuelven el primero y el último.

    + +

    Eeeehhh pero … si tengo un Set o un Bag, ¿ cómo accedo a los elementos de un Bag o un Set? Eso … viene más adelante. Veamos ahora las variantes de colecciones ordenadas.

    + +

    La primera que les presentaremos es la OrderedCollection. Esta colección ordena sus elementos, y el criterio es el orden en cual fueron agregados a la colección. Entonces si creo mi colección así

    + +

    miCol := OrderedCollection new.  +miCol add: 'hola'.  +miCol add: 'queridos'.  +miCol add: 'amigos'.  +miCol add: 'escandinavos'. 

    + +

    después puedo pedirle varias cosas

    + +

    miCol first <- el primero - 'hola' +miCol last <- el último - 'escandinavos' +miCol at: 3 <- el tercero - 'amigos' +miCol at: 4 <- el cuarto - 'escandinavos' +miCol size <- cantidad de elementos - 4

    + +

    y después puedo seguir agregándole elementos, ante lo cual la colección “se estira”

    + +

    miCol add: 'agrego'.  +miCol add: 'cosas'.  +miCol size <- cantidad de elementos ahora - 6 +miCol last <- el último ahora - 'cosas'

    + +

    Luego, así como la OrderedCollection, también tenemos la llamada SortedCollection, que la diferencia con la primera radica en que el criterio de ordenamiento puede ser definido. Si no definimos el criterio, SortedCollection ordena los elementos por su “orden natural” (significa que los ordenará de menor a mayor). Dicho de otra forma, no ordena por orden de llegada, sino por comparación entre los elementos.

    + +

    Si queremos ordenar los elementos de la colección con un criterio en particular, necesitamos pasárselo a la colección. La forma de hacerlo, es pasarle lo que denominamos sortBlock, que es un objeto Block (bloque).

    + +

    Con respecto a las colecciones que tienen orden, por último veremos al viejo amigo Array. Aquí en Smalltalk también existe, y una de sus características es que es de tamaño fijo. Para instanciar un Array, hago Array new: 6, donde 6 es la cantidad de elementos que contendrá, alternativamete si conocemos los elementos de antemano pueden crearse de forma literal (que es uno de los pocos motivo razonable para querer usar un Array en vez de otro tipo de colección como OrderedCollection).

    + +

    Los Arrays no implementan el mensaje add:, justamente porque no puedo modificar su tamaño. La forma de agregarles elementos es a través del mensaje at:put:, como por ejemplo:

    + +

    miVector := Array new: 2.  +miVector at: 1 put: unaLata. 

    + +

    Todas las colecciones entienden una serie de mensajes que permiten obtener distintos sabores de colecciones con los mismos elementos. Estos mensajes son de la forma “as{ColeccionQueQuiero}”. Vamos a un par de ejemplos para ver cómo funciona.

    + +

    Si tuviese una colección de la clase Bag, y quiero sacarle los repetidos, sé que el Set no tiene repetidos, entonces tomo mi colección como un Set. Entonces:

    + +

    sinRepetidos := miCarrito asSet. 

    + +

    Si tuviese un array, y lo quiero convertir en una colección de tamaño variable, podría hacer:

    + +

    coleccionVariable := miVector asOrderedCollection. 

    + +

    Si quisiera ordenar mi carrito de compras del producto más caro al más barato, haría algo como:

    + +

    ordenadosPorPrecio := miCarrito asSortedCollection: [:unProd :otroProd | unProd precio > otroProd precio]. 

    + +

    El mensaje asSortedCollection: recibe un parámetro que, obviamente, es un sortBlock. El sortBlock es un bloque que necesita 2 parámetros. El código del bloque es un código que debe devolver true o false. Para ordenar los objetos dentro de la colección, se evalúa el código y si el objeto retornado es true, el primer parámetro va antes que el segundo. Si retorna false, el segundo parámetro se ubica antes que el primero.

    + +

    También está el mensaje asSortedCollection (o sea sin el dos-puntos, o sea que no requiere parámetro) que, como dijimos antes, ordenará los elementos por el “orden natural”.

    + +

    ¿Cuál es el “orden natural”? Dijimos que si a una SortedCollection no le decimos cómo queremos que ordene los elementos, los ordena por el “orden natural”. Pero … ¿qué puede ser este “orden natural”?

    + +

    Si estoy en el paradigma de objetos … seguro va a tener que ver con objetos y mensajes. El “orden natural” es el que dicta el mensaje <, que es binario. O sea, en una SortedCollection con “orden natural” el criterio es poner a elem1 antes que elem2 si el resultado de evaluar elem1 < elem2 es true.

    + +

    Claro, eso quiere decir que solamente voy a poder tener, en una SortedCollection con “orden natural”, objetos que entiendan el mensaje <. Los números, los String, las fechas, todos esos entienden <. Pero p.ej. si quiero poner latas en una SortedCollection, no puede ser por “orden natural”, tengo que especificar el orden con el bloque con dos parámetros como vimos hace un ratito.

    + +

    Jerarquía de Colecciones (En Pharo)

    + +

    Aquí se provee una imagen con una jerarquía simplificada de las colecciones existentes en Pharo. Presten especial atención a las clases explicadas en este artículo, las demás se proveen por motivos de completitud.

    + +

    Jerarquía de colecciones en Pharo Smalltalk

    + +

    Diccionarios

    + +

    Por último, queremos mostrarles un sabor de colección que es especial. Se llama Dictionary y, como su nombre lo indica, intenta representar un diccionario. Este tipo de representación implica tener una asociación entre una clave y un valor.

    + +

    Poniendo como ejemplo, el propio diccionario. El diccionario es una asociación entre una clave, que son cada letra del abecedario y un apartado de páginas que tienen palabras. El diccionario lleva todo una explicación aparte, pueden profundizar más al respecto leyendo sobre Diccionarios.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/salsa-jack-daniel-s.html b/wiki/articles/salsa-jack-daniel-s.html new file mode 100644 index 0000000000..0274c745bc --- /dev/null +++ b/wiki/articles/salsa-jack-daniel-s.html @@ -0,0 +1,328 @@ + + + + + + + + + + + Salsa jack daniel s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Salsa jack daniel s +

    +
    + + + +
    +

    Ingredientes

    + +
      +
    • 1 tea spoon cebolla en polvo
    • +
    • 1 table spoon salsa tabasco
    • +
    • 1/4 cup jack daniels
    • +
    • 2 table spoon vinagre de vino
    • +
    • 2 cup azucar rubia
    • +
    • 1/4 cup agua
    • +
    • 2 calditos de carne
    • +
    • 2 table spoons worcestershire
    • +
    + +

    Pasos:

    + +
      +
    1. Mezclar todo en una cacerola y hasta que hierva (ojo porque sube…)
    2. +
    3. Dejar sobre el fuejo 10 minutos más, a fuego bajo.
    4. +
    5. Dejar que se enfríe unos minutos antes de servir.
    6. +
    + +

    NOTA: Las medidas están en unidades americanas:

    + +
      +
    • 1 tea spoon = 4.92 mililitros
    • +
    • 1 table spoon = 14.79 mililitros
    • +
    • 1 cup = 236.58 mililitros
    • +
    + +

    NOTA2: Es importante que no se pase de fuego o se va a hacer una pasta, tipo caramelo. Para evitar eso, conviene tirar cada tanto unas gotitas sobre el mármol, hasta ver que al enfriarse se espesa, sin endurecerse. En caso de pasarse se puede cortar con un chorro de agua fría y volver a dejar que hierva.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/scala.html b/wiki/articles/scala.html new file mode 100644 index 0000000000..0a9be02b5e --- /dev/null +++ b/wiki/articles/scala.html @@ -0,0 +1,348 @@ + + + + + + + + + + + Scala + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Scala +

    +
    + + + +
    +

    Sobre el lenguaje:

    + + + +

    Herramientas basadas en Scala:

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/self---pseudovariable.html b/wiki/articles/self---pseudovariable.html new file mode 100644 index 0000000000..eb229f9da4 --- /dev/null +++ b/wiki/articles/self---pseudovariable.html @@ -0,0 +1,399 @@ + + + + + + + + + + + Self pseudovariable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Self pseudovariable +

    +
    + + + +
    +

    self es una pseudovariable que siempre referencia al objeto receptor del mensaje que hizo que se evalúe el método que estamos analizando en un momento dado. Tené en cuenta que no es posible asignar self, esta referencia es manejada por la máquina virtual, no por el programador.

    + +

    Sirve para que el objeto receptor pueda mandarse un mensaje a sí mismo dentro de la implementación del método que se está ejecutando o para que, al mandar un mensaje a otro objeto que necesite colaborar con él, pueda pasarse a sí mismo por parámetro.

    + +

    Ejemplo en Wollok:

    + +

    Si tenemos este envío de mensaje:

    + +

    pepita.vola(10)

    + +

    y pepita está definida de la siguiente forma:

    + +
    object pepita {
    +  var energia = 100
    +  
    +  method energia(){
    +    return energia
    +  }
    +  
    +  method energia(nuevaEnergia){
    +    energia = nuevaEnergia
    +  }
    +  
    +  method vola(unosKms){
    +    self.energia(self.energia() - unosKms)
    +  }
    +}
    +
    + +

    Cuando se le mande el mensaje para volar 10 kilómetros a pepita, se va a ejecutar el método que envía los mensajes para obtener y modificar la energía a self, o sea que pepita va a ser quien reciba ambos mensajes.

    + +

    Como se mencionó antes, en cualquier método es perféctamente válido parametrizarse a uno mismo, por ejemplo:

    + +
    object pepita {
    + method teEntrena(unEntrenador) {
    +   self.come(50)
    +   unEntrenador.entrenaA(self)
    + }
    +}
    +
    + +

    Los mismos ejemplos anteriores, pero en Smalltalk:

    + +

    Envío de mensaje inicial:

    + +

    pepita vola: 10.

    + +

    Método que se ejecutaría:

    + +
    >> vola: unosKms
    +   self energia: self energia - unosKms
    +
    + +

    Parametrización de self:

    + +
    >> teEntrena: unEntrenador
    +   self come: 50.
    +   unEntrenador entrenaA: self.
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/self.html b/wiki/articles/self.html new file mode 100644 index 0000000000..5876b3484c --- /dev/null +++ b/wiki/articles/self.html @@ -0,0 +1,337 @@ + + + + + + + + + + + Self + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Self +

    +
    + + + +
    +

    self - pseudovariable

    + +

    Self - Lenguaje de programación:

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/sintaxis-de-smalltalk.html b/wiki/articles/sintaxis-de-smalltalk.html new file mode 100644 index 0000000000..a60969ba87 --- /dev/null +++ b/wiki/articles/sintaxis-de-smalltalk.html @@ -0,0 +1,354 @@ + + + + + + + + + + + Sintaxis de smalltalk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Sintaxis de smalltalk +

    +
    + + + +
    +

    La sintaxis de Smalltalk es bastante particular, pero sigue unas pocas reglas generales fáciles de aprender:

    + +

    La regla principal es que lo primero de la sentencia es un objeto seguido por el mensaje que le queremos mandar, el cual podría o no recibir parámetros. Por ejemplo:

    + +

    pepita energia

    + +

    El objeto receptor será aquel referenciado por la variable llamada pepita, al cual se le está mandando el mensaje energia que no recibe parámetros.

    + +

    4 + 5

    + +

    El objeto receptor es el número 4 y recibe el mensaje + con el parámetro 5.

    + +

    pepita vola: 10

    + +

    El objeto receptor será aquel referenciado por la variable llamada pepita, al cual se le está mandando el mensaje vola: con el parámetro 10. Más sobre este tema en Tipos de mensajes en Smalltalk.

    + +

    Pero qué pasa con los elementos del lenguaje que no son envíos de mensajes?

    + +

    Las sentencias se separan con un punto (es separador, no terminador, por eso no siempre hace falta escribirlo)

    + +

    pepita vola: 20. +pepita energia

    + +

    Este código primero hace que pepita vuele 20 y luego consulta su energia. En cambio esto…

    + +

    pepita vola: 20 +pepita energia

    + +

    … va a tratar de mandarle el mensaje pepita al número 20 (lo cual claramente no es lo que queríamos) y como no va a entender ese mensaje, va a tirar un error.

    + +

    Para asignar una variable se usa := que no es un mensaje a un objeto, en el método vola: de pepita (que tiene un atributo energia) podríamos tener lo siguiente:

    + +

    vola: metrosAVolar +  energia := energia - 40 - metrosAVolar

    + +

    Lo que va a suceder es que la referencia llamada energia va a modificarse, de modo que su nuevo valor será el resultado de la expresión energia - 40 - metrosAVolar. Sólo se puede tener una referencia a la izquierda del :=, es lo único que puede ser asignado.

    + +

    Para retornar el valor de una expresión en un método se usa el circunflejo ^, podríamos definirle el siguiente método a pepita para retornar un booleano que diga si pepita tiene hambre

    + +

    tenesHambre +  ^ energia < 20

    + +

    El retorno corta la ejecución del método, motivo por el cual no tiene sentido tener otra sentencia luego de ^ energia < 20, ya que nunca se va a evaluar.

    + + + + + + + + +
    En caso de que querramos definir variables locales para un método, se usan pipescomo se explica en Variables locales en métodos
    + +

    Y los paréntesis se usan para delimitar partes de una expresión, por ejemplo para indicar dónde comienza y dónde termina un envío de mensajes para pasar por parámetro a otro mensaje el resultado de dicha evaluación. Sabiendo bien cómo trabaja la precedencia es posible ahorrarse muchos paréntesis innecesarios haciendo que sea más fácil de leer.

    + +

    Importante! No confundir paréntesis ( ) con corchetes [ ]. Los corchetes se usan para construir bloques.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/smalltalk.html b/wiki/articles/smalltalk.html new file mode 100644 index 0000000000..030010a974 --- /dev/null +++ b/wiki/articles/smalltalk.html @@ -0,0 +1,362 @@ + + + + + + + + + + + Smalltalk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Smalltalk +

    +
    + + + +
    +

    Algunos links útiles para los que quieran conocer un poco más sobre uno de los lenguajes más viejitos:

    + + + +

    Sobre (algunos de) los distintos sabores de Smalltalk:

    + + + +

    Herramientas basadas en Smalltalk:

    + + + +

    Y la comunidad de Smalltalk:

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/sobre-el-uso-del-igual-----en-prolog.html b/wiki/articles/sobre-el-uso-del-igual-----en-prolog.html new file mode 100644 index 0000000000..22efdb7443 --- /dev/null +++ b/wiki/articles/sobre-el-uso-del-igual-----en-prolog.html @@ -0,0 +1,462 @@ + + + + + + + + + + + Sobre el uso del igual en prolog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Sobre el uso del igual en prolog +

    +
    + + + +
    +

    Descripción del problema

    + +

    Vamos a estudiar éste caso:

    + +
      +
    • “Dos personas son hermanastros cuando tienen igual padre y diferente madre”
    • +
    + +

    El is sólo se usa para cuentas, las cuentas sólo se hacen con is

    + +

    Ésta solución funciona, pero es conceptualmente errónea:

    + +
    hermanastros(Hermano1,Hermano2):-
    +   padre(Hermano1,Padre1),
    +   padre(Hermano2,Padre2),
    +   madre(Hermano1,Madre1),
    +   madre(Hermano2,Madre2),
    +   Padre1 is Padre2,  %%% Acá está el error
    +   Madre1 \= Madre2.
    +
    + +

    Si el is sólo sirve para cuentas,

    + +
      +
    • No es conceptualmente correcto hacer <algo> is Variable.
    • +
    • No es conceptualmente correcto hacer <algo> is 4.
    • +
    + +

    Si bien funciona, debemos usar las herramientas para lo que corresponde. Cuando una persona lee un is, espera cuentas. Debemos usar las abstracciones que comuniquen correctamente nuestras ideas.

    + +

    Si las cuentas sólo se hacen con is,

    + +
      +
    • Esto ni siquiera funciona: Variable = 5 * 3..
    • +
    • Esto ni siquiera funciona: factorial(N+1,Fac). (¡Hay una cuenta, y falta un is!)
    • +
    + +

    La razón por la que Variable = 5 * 3. no funciona es que el = es “tonto”, se fija que a izquierda y a derecha haya exactamente lo mismo. Ver aritmética en prolog.

    + +

    La razón por la que factorial(N+1,Fac). no funciona es que la unificación que realiza prolog de valor con variable es igual de “tonta” que el =. Salvo que yo ponga un is, no se va a resolver ninguna cuenta.

    + +

    Entonces:

    + +
      +
    • vale Resultado is Variable + 1. (Siempre que Variable venga unificada).
    • +
    + +

    Más abajo la solución certera.

    + +

    Variable = OtraVariable

    + +

    Ésta solución funciona, pero es conceptualmente errónea:

    + +
    hermanastros(Hermano1,Hermano2):-
    +   padre(Hermano1,Padre1),
    +   padre(Hermano2,Padre2),
    +   madre(Hermano1,Madre1),
    +   madre(Hermano2,Madre2),
    +   Padre1 = Padre2,  %%% Acá está el error
    +   Madre1 \= Madre2.
    +
    + +

    ¿Por qué está mal? Porque tiene cierta imperatividad, en donde nosotros estamos forzando a mano que los padres sean iguales, y que las madres sean diferentes.

    + +

    La idea de verificación que nos ofrece Lógico nos permite representar una igualdad de manera mucho más sencilla, más directa. Sabiendo que Prolog considera cierta una consulta si sus variables matchean, y falsas si no, podemos hacer las cosas más declarativas:

    + +

    Si el padre es el mismo, entonces, que sea la misma variable. Éste código funciona, y es conceptualmente correcto:

    + +
    hermanastros(Hermano1,Hermano2):-
    +   padre(Hermano1,Padre), %%% Usamos variable Padre
    +   padre(Hermano2,Padre), %%% Usamos misma variable Padre
    +   madre(Hermano1,Madre1),
    +   madre(Hermano2,Madre2),
    +   Madre1 \= Madre2.
    +
    + +

    Así se aprovechan mejor las herramientas mencionadas, y redujimos un poco la imperatividad.

    + +

    Que dos variables tengan el mismo nombre, es una restricción implícita de igualdad

    + +

    Por otro lado, en el caso de las variables Madre1 y Madre2, como las variables con nombres diferentes no representan una restricción de diferencia, tenemos que forzar dicha restricción con el \=.

    + +

    Variable = individuo

    + +

    Tomemos el siguiente problema: “Un instrumento suena lindo si es de cuerda y está afinado”.

    + +

    Solución:

    + +
    suenaLindo(Instrumento):-
    +    tipo(Instrumento,Tipo), %%% Pido el tipo
    +    Tipo = cuerda,          %%% comparo con cuerda.
    +    estaAfinado(Instrumento).
    +
    + +

    Eso funciona, pero está conceptualmente mal.

    + +

    ¿Por qué? Veamos:

    + +
      +
    • La unificación de una variable se da una sola vez en la ejecución.
    • +
    + +

    Eso significa que, en un programa en lógico, los valores de las variables no cambian con el tiempo (una vez unificadas). En nuestro caso, una vez unificado con cuerda, la variable Tipo siempre es cuerda.

    + +
      +
    • La unificación se da para todas las ocurrencias de la misma, e instantáneamente
    • +
    + +

    Eso significa que, en un programa en lógico, la variable “vale” lo mismo en cualquier parte de la regla. En nuestro caso, al unificarse Tipo con algún tipo en la 2da línea, eso “llena” la variable automáticamente en la 3era línea. ¡Y no puede cambiar el valor!

    + +

    En consecuencia, decir Tipo = cuerda es exactamente lo mismo que escribir cuerda en todos los lugares donde escribimos Tipo. La solución correcta:

    + +
    suenaLindo(Instrumento):-
    +    tipo(Instrumento,`cuerda`),
    +    estaAfinado(Instrumento).
    +
    + +

    Es muy común ver este tipo de errores en predicados polimórficos y con functores. Ésto funciona, pero está conceptualmente mal:

    + +
    potencia(Habilidad,Potencia):-
    +     Habilidad = velocista(VelMax),
    +     Potencia = VelMax.
    +
    + +

    Ésta es la forma correcta:

    + +
    potencia(velocista(VelMax),VelMax).
    +
    + +

    Conclusión

    + +

    El igual es necesario en contados casos. La mayoría de las veces uno se puede arreglar con la metáfora de identidad de lógico, y con un poquito de unificación y pattern matching.

    + +

    Usemos con criterio las herramientas y conceptos que nos da el paradigma.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/super.html b/wiki/articles/super.html new file mode 100644 index 0000000000..ee6a334597 --- /dev/null +++ b/wiki/articles/super.html @@ -0,0 +1,454 @@ + + + + + + + + + + + Super + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Super +

    +
    + + + +
    +

    super es una pseudovariable muy parecida a self.

    + +

    super referencia (apunta) al objeto receptor del mensaje del método que estamos analizando en un momento dado al igual que self. La diferencia entre self y super es que super afecta al method lookup

    + +

    Problema que resuelve

    + +

    Sin la existencia de super tendríamos problemas para resolver ciertos problemas, por ejemplo si tenemos la siguiente jerarquía de clases A ⇽ B:

    + +
    #A >> m
    +   "lógica definida por A para cuando se recibe el mensaje m"
    +   ^ 'hola'
    +#B >> m
    +   "queremos usar la lógica que define A y además hacer otra cosa"
    +   ^ self m , ' mundo'
    +
    + +

    Si a una instancia de B le mandamos el mensaje m ejecutará el método m definido en B y en su definición se manda a sí mismo m, con lo cual se ejecuta ese mismo método (no el de A) y así indefinidamente. Para solucionar este problema podemos usar super.

    + +
    #A >> m
    +   "lógica definida por A para cuando se recibe el mensaje m"
    +   ^ 'hola'
    +#B >> m
    +   "queremos usar la lógica que define A y además hacer otra cosa"
    +   ^ super m , ' mundo'
    +
    + +

    Cuando en un método se manda un mensaje a super el method lookup se ve modificado empezando la búsqueda del método correspondiente a ese mensaje en la clase inmediatamente superior a donde está definido ese método, en vez de en la clase de la cual es instancia el objeto. De esta forma podemos redefinir un método de la superclase para agregar lógica nueva y a su vez reutilizar el comportamiento heredado.

    + +

    Supongamos que tenemos la siguiente jerarquía de clases A ⇽ B ⇽ C que definen:

    + +
    #A >> m
    +   ^ self n + 4
    +   >> n
    +   ^ 1
    +#B >> m
    +   ^ super m + 5
    +#C >> n
    +   ^ 3
    +
    + +

    Sabiendo que tanto self como super apuntan a i, o sea, ambos apuntan al objeto receptor del mensaje, analicemos lo que pasa si evaluamos lo siguiente:

    + +
    i := C new.
    +i m.
    +
    + +

    Cuando i recibe el mensaje m busca un método en su clase C con el mismo nombre y no lo encuentra, con lo cual lo sigue buscando en la superclase de C, que es B. Allí existe una definición para ejecutar y vemos que al objeto referenciado por super (que es i) se le manda el mensaje m, haciendo que el method lookup para ese mensaje comience en la clase A (superclase de donde está definido el método). La definición de #A>>m envía el mensaje n al objeto referenciado por self (que también es i), pero el method lookup para encontrar el método n comienza desde la clase de la cual es instancia i (o sea en C).

    + +

    El resultado final del cálculo sería: 3 + 4 + 5

    + +

    Si le mandáramos el mensaje m a una instancia de B el resultado sería: 1 + 4 + 5, ya que se ejecutaría #B>>m que hace self n, se empieza a buscar n en B, no se encuentra, se lo busca en A y retorna 1.

    + +

    Resumen

    + +
      +
    • Si el receptor del mensaje NO es super, se busca en la clase de la cual es instancia el objeto un método con el mismo nombre del mensaje.
    • +
    • Si el receptor del mensaje ES super entonces se busca la definición en la superclase de la clase en donde está el método que contiene a la pseudovariable super.
    • +
    + +

    Conclusión

    + +

    super sólo debe usarse para redefinir métodos que envían el mismo mensaje que se está definiendo, para evitar loops que se provocarían en el method lookup usando self

    + +

    Malos usos de super

    + +

    Caso 1

    + +

    Supongamos que tenemos este código para la jerarquía A ⇽ B (O sea B es subclase de A)

    + +

    Código erróneo:

    + +
    #A >> m1
    +  "hace algo"
    +#B >> m1
    +  super m1
    +
    + +

    Esta redefinición usando super es innecesaria, ya que si a una instancia de B se le manda m1 el mismo method lookup buscará la definición en A en caso de no encontrarla en B. Es además incorrecta, porque al redefinir un método semánticamente estoy indicando que “hago las cosas distintas a arriba”, cuando éste no es el caso.

    + +

    Código correcto:

    + +
    #A >> m1
    +  "hace algo"
    +
    + +

    ¡No hace falta escribir nada, B ya entiende el mensaje m1!

    + +

    Caso 2

    + +

    Otro error muy común (y muy grave) es usar super para mandar un mensaje con nombre diferente al método que se está definiendo: (C hereda de B, B hereda de A)

    + +

    Código erróneo:

    + +
    #A >> m1
    +   ^ 1
    +#B >> m2
    +   ^ super m1 + 5
    +#C >> m1
    +   ^ 3
    +
    + +

    En este ejemplo se puede ver que se manda el mensaje m1 en B usando super en vez de self en el método m2. Esto es un problema ya que se ignora el comportamiento que puedan tener para m1 las subclases de B así como una posible implementación futura de m1 para B. Este mal uso de super suele llevar a un comportamiento inesperado del sistema que puede no resultar en un error como sucede en este caso (retornaría 6 en vez de 8), con lo cual es muy difícil de detectar y corregir.

    + +

    Código correcto:

    + +
    #A >> m1
    +   ^ 1
    +#B >> m2
    +   ^ self m1 + 5
    +#C >> m1
    +   ^ 3
    +
    + +

    ¡Si yo soy un B, quiero hacer m1 como un B! Siempre voy a querer comportarme como me corresponde a mí. Que ese método esté definido en la superclase es una coincidencia. Si yo quiero hacer m1, entonces hago self m1. (Releer la conclusión)

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/tecnicas-avanzadas-de-programacion.html b/wiki/articles/tecnicas-avanzadas-de-programacion.html new file mode 100644 index 0000000000..a86d5c31ad --- /dev/null +++ b/wiki/articles/tecnicas-avanzadas-de-programacion.html @@ -0,0 +1,423 @@ + + + + + + + + + + + Tecnicas avanzadas de programacion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Tecnicas avanzadas de programacion +

    +
    + + + +
    +

    Técnicas Avanzadas de Programación - Contenidos actuales

    + +

    Modelado en objetos avanzado

    + + + +

    Tipado dinámico vs estático en objetos

    + + + +

    Metaprogramación

    + + + +

    Declaratividad y DSLs

    + + + +

    Técnicas Avanzadas de Programación - Contenidos heredados

    + +

    La materia cambió mucho sus contenidos en estos años, sin embargo el material teórico sigue siendo útil aunque no esté en la planificación actual.

    + +

    Material teórico

    + + + +

    Arquitecturas

    + + + +

    Tutoriales

    + + + +

    Consejos prácticos

    + + + +

    Otros

    + + + +

    Apuntes para revisar

    + + + +

    Una lectura interesante

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/template-method.html b/wiki/articles/template-method.html new file mode 100644 index 0000000000..ca40438fed --- /dev/null +++ b/wiki/articles/template-method.html @@ -0,0 +1,408 @@ + + + + + + + + + + + Template method + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Template method +

    +
    + + + +
    +

    Para calcular el precio de un producto, tenemos que considerar

    + +
      +
    • todos los productos tienen un precio de venta base
    • +
    • los productos importados tienen un cargo extra determinado por el peso (300 $ x cada kilo)
    • +
    • a los productos nacionales se les suma un adicional del 10% de impuestos internos
    • +
    • y finalmente otros productos especiales incorporan un extra de 5 $ si el producto pesa más de 4 kg.
    • +
    + +

    Si elegimos modelar los productos mediante una jerarquía de subclasificación, tenemos

    + +
      +
    • Una superclase Producto, con 3 subclases +
        +
      • ProductoImportado
      • +
      • ProductoNacional
      • +
      • ProductoEspecial
      • +
      +
    • +
    + +

    ¿Dónde ubicamos la responsabilidad de determinar el precio de un producto?

    + +

    Pensamos primero en cómo resolver el precio de venta de un producto Importado

    + +

    metodo precioVenta()  +    precioVentaBase + (300 * peso)   +fin

    + +

    </code>

    + +

    Y el producto nacional

    + +

    metodo precioVenta()  +    precioVentaBase + precioVentaBase * 0.10 +fin

    + +

    </code>

    + +

    El template method es una técnica que permite agrupar algoritmos similares, donde

    + +
      +
    • la superclase define cómo es el algoritmo principal
    • +
    • cada subclase define comportamiento específico de una parte de ese algoritmo
    • +
    + +

    Entonces en la clase producto definimos que el precio de venta sale del precio de venta base, y le pedimos a cada subclase que implemente el costo adicional:

    + +

    + +

    metodo precioVenta()  +    precioVentaBase + self costoAdicional +fin

    + +

    </code>

    + +

    En lenguajes con chequeo de tipos, Producto debe tener definido un costoAdicional en su interfaz. Esto se puede implementar

    + +
      +
    • con un comportamiento default (por ejemplo, haciendo que costoAdicional devuelva 0)
    • +
    • o bien con un método abstracto (abstract method), que obliga a redefinir el método en las subclases
    • +
    + +

    Vemos la implementación en xtend:

    + +

    + +

    def double precioVenta() { +    precioVentaBase + this.costoAdicional +}

    + +

    def double costoAdicional()   // abstract method

    + +

    </code>

    + +

    En lenguajes con tipado dinámico se puede definir un método que explícitamente devuelva error para obligar a las subclases a implementar cada operación primitiva. Vemos el ejemplo en Smalltalk:

    + +

    + +

    precioVenta +     ^precioVentaBase + self costoAdicional

    + +

    costoAdicional +     self subclassResponsibility

    + +

    </code>

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/testeo-unitario-avanzado.html b/wiki/articles/testeo-unitario-avanzado.html new file mode 100644 index 0000000000..e6bae56897 --- /dev/null +++ b/wiki/articles/testeo-unitario-avanzado.html @@ -0,0 +1,669 @@ + + + + + + + + + + + Testeo unitario avanzado + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Testeo unitario avanzado +

    +
    + + + +
    +

    Este artículo presenta algunas guías para desarrollar los casos de prueba, considerando que ya tienen una base de testeo unitario automatizado. Si estás buscando un apunte, te recomendamos el siguiente apunte de Testing.

    + +

    Por otra parte, aquí explicamos la mecánica utilizando JUnit 5 como framework de testeo, si estás buscando una variante al estilo XSpec, como Kotest, podés ver esta página.

    + +

    Ejemplo

    + +

    Un sistema de seguros de automotor define en qué casos se puede pagar un siniestro:

    + +
      +
    • para los clientes normales, si no son morosos (la deuda debe ser 0)
    • +
    • para las flotas de autos, se soporta una deuda de hasta $ 10.000 si el cliente tiene más de 5 vehículos ó hasta $ 5.000 en caso contrario
    • +
    + +

    Definiendo los escenarios

    + +

    En base al ejemplo anterior, podemos considerar los siguientes escenarios:

    + +
      +
    • un cliente normal moroso: si debe $ 1 ó $ 50.000 no nos importa, porque está en la misma clase de equivalencia
    • +
    • una flota con menos de 5 autos (ó 5 autos) => serían “pocos” autos
    • +
    • una flota con más de 5 autos => serían “muchos” autos
    • +
    + +

    Elegimos cuántos autos en base al valor límite: como a partir de los seis autos se considera mucho y menos de 6 son “pocos” autos, 6 es el valor de una flota con muchos autos, 5 es el valor de una flota con pocos autos.

    + +

    Estructura de los tests

    + +

    La estructura que tienen los tests en base a los escenarios propuestos podría ser:

    + +
    +
    +
    +      dado un cliente normal
    +  ├── que es moroso: no puede cobrar un siniestro
    +  └── que no es moroso: puede cobrar un siniestro
    +dado un cliente de flota con muchos autos (6 autos)
    +  ├── si el cliente debe más de $ 10.000 no puede cobrar un siniestro
    +  └── si el cliente debe $ 10.000 o menos, puede cobrar un siniestro
    +dado un cliente de flota con pocos autos (5 autos)
    +  ├── si el cliente debe más de $ 5.000 no puede cobrar un siniestro
    +  └── si el cliente debe $ 5.000 o menos puede cobrar un siniestro
    +
    +    
    +
    +
    + +

    Definiendo las clases y las variables de los tests

    + +

    Necesitamos

    + +
      +
    • un cliente normal
    • +
    • una flota de 6 autos
    • +
    • otra flota de 5 autos
    • +
    + +

    a los que podemos configurar diferentes grados de deuda. Podemos seguir algunas recomendaciones adicionales:

    + +

    Agrupar los escenarios en clases

    + +

    ¿Cuántas clases necesitamos para implementar los casos de prueba? Podríamos considerar una clase sola para todos los tests, o bien tener dos clases: una para clientes normales y otra para clientes de flota, o bien podríamos tener una clase para cada uno de los escenarios que planteamos más arriba (cliente normal moroso, cliente que no debe nada, flota de 6 autos, etc.)

    + + +


    +Tener en una sola clase todos los tests no resulta ser una buena práctica, porque

    + +
      +
    • dificulta diferenciar los escenarios, estarán todas las variables de los tests mezcladas
    • +
    • si construimos un fixture con cada uno de los tipos de cliente en el setup, estamos penalizando a cada uno de los tests por lo que necesitan los demás: ¿tiene sentido crear un cliente de flota con 5 autos si estoy testeando un cliente que tiene 6?
    • +
    • la clase a testear pierde cohesión, está cubriendo todos los casos de prueba
    • +
    + + +


    +Volviendo al ejemplo, hay varias opciones posibles:

    + +
      +
    • tener una clase para clientes normales y otra para clientes de flota
    • +
    • tener una clase para clientes normales, otra para flota con pocos autos y otra para flota con muchos autos
    • +
    + + +


    +Crearemos entonces estas clases de test:

    + +
      +
    • ClienteNormalTest
    • +
    • FlotaPocosAutosTest
    • +
    • FlotaMuchosAutosTest
    • +
    + +

    Es importante que no haya demasiados detalles de implementación en los nombres: FlotaCon5AutosTest o FlotaCon6AutosTest está sujeto a que cualquier cambio del negocio respecto a lo que son “muchos” o “pocos” autos necesite modificar el nombre de la clase.

    + +

    Intention revealing - parte 1

    + +

    Queremos expresar lo más claramente posible la intención de la clase: qué clase de equivalencia está testeando. El nombre ayuda, e incluso JUnit 5 nos permite incorporar la anotación @DisplayName para describir el escenario en lenguaje castellano:

    + +
    +
    +
    +      @DisplayName("Dado un cliente de flota con muchos autos")
    +class FlotaMuchosAutosTest {
    +
    +    
    +
    +
    + +

    recordando que las clases agrupan los tests, más adelante veremos cómo juega a favor este encabezado escrito en lenguaje natural. Una vez más recordamos: “muchos autos” es mejor que decir “6 autos”. En otras palabras, explicitar el caso de prueba y no el dato de prueba: 6 autos es un dato concreto, pero lo que representa es el caso de prueba de una flota con muchos autos.

    + +

    Expresividad en los tests

    + +

    Un primer approach

    + +

    Para crear nuestro fixture de una flota con muchos autos, los enunciados suelen traer ejemplos como: “Lidia Pereyra tiene una flota con 6 autos”. Es tentador escribir un test como el siguiente:

    + +
    +
    +
    +      	Flota pereyra
    +	
    +	@BeforeEach
    +	def void init() {
    +		pereyra = new Flota => [
    +			agregarAuto(new Auto("ab028122", 2008))
    +      // ... se agregan más autos ... //
    +		]
    +	}
    +
    +	@Test
    +	def void pereyraNoPuedeCobrarSiniestro() {
    +		pereyra.generarDeuda(15000)
    +		assertFalse(pereyra.puedeCobrarSiniestro)
    +	}
    +
    +    
    +
    +
    + +

    Pero ¿qué pasa si hay un error en el código de negocio? Supongamos esta implementación, donde la clase Cliente tiene la definición de la deuda como un entero:

    + +
    +
    +
    +      class Flota extends Cliente {
    +	List<Auto> autos = newArrayList
    +	
    +	override puedeCobrarSiniestro() {
    +		this.deuda < this.montoMaximoDeuda
    +	}
    +	
    +	def montoMaximoDeuda() {
    +		if (autos.size > 5) 20000 else 5000 // debería ser 10.000 y no 20.000
    +	}
    +
    +    
    +
    +
    + +

    Cuando ejecutamos el test tenemos muy poca información relevante:

    + +

    + mal nombre de variable +

    + +
      +
    • la variable pereyra no está revelando que es un cliente de flota con muchos autos
    • +
    • y tampoco está claro por qué no puede cobrar el siniestro el cliente.
    • +
    + +

    Al fallar la condición tenemos que bucear en el código y extraer este dato para determinar si el error está en el test o en el código de negocio.

    + +

    Una segunda oportunidad

    + +

    Vamos a mejorar la semántica del test, renombrando la variable pereyra por un nombre más representativo de la clase de equivalencia que estamos modelando, agregando la anotación @DisplayName para el test y definiendo un mensaje de error adicional en el assert:

    + +
    +
    +
    +      class FlotaMuchosAutosTest {
    +	
    +	Flota flotaConMuchosAutos
    +	
    +	@BeforeEach
    +	def void init() {
    +		flotaConMuchosAutos = new Flota => [
    +			agregarAuto(new Auto("ab028122", 2008))
    +      // ... agregamos más autos ... //
    +		]
    +	}
    +
    +	@Test
    +	@DisplayName("si tiene una deuda grande no puede cobrar un siniestro")
    +	def void conDeudaGrandeNoPuedeCobrarSiniestro() {
    +		flotaConMuchosAutos.generarDeuda(15000)
    +		assertFalse(flotaConMuchosAutos.puedeCobrarSiniestro, 
    +      "una flota que tiene una deuda abultada no puede cobrar un siniestro")
    +	}
    +
    +    
    +
    +
    + +

    Ahora al fallar el test sabemos más cosas:

    + +

    + mas expresividad en los tests +

    + +
      +
    • el test con su stack trace, pero también
    • +
    • qué es lo que estamos testeando, tratando de no entrar en detalles para no duplicar lo que dice el código
    • +
    • qué se esperaba que pasara y no pasó, en un formato legible para un usuario: “Dado un cliente de flota con muchos autos, si tiene una deuda grande no puede cobrar un siniestro”
    • +
    + + +

    +
    +

    + +

    AAA Pattern

    + +

    Los tests suelen estructurarse según el patrón AAA: Arrange, Act y Assert.

    + +
      +
    • Arrange: donde instanciamos los objetos a testear, con sus colaboradores: en el ejemplo son la flota y sus autos. Cuando los contextos son compartidos, los frameworks basados en xUnit (JUnit5 es uno de ellos) nos permiten ubicarlo en un método setup (@BeforeEach). La desventaja de esta técnica es que para tener una idea general de los elementos que participan en el test debemos mirar el test y el setup, por eso una alternativa suele ser tener métodos en el test que construyen el escenario que se necesita:
    • +
    + +
    +
    +
    +      	@Test
    +	def void conDeudaGrandeNoPuedeCobrarSiniestro() {
    +    // Arrange
    +		val flotaConMuchosAutos = this.crearFlotaDeAutos(6)
    +
    +    // Act
    +    flotaConMuchosAutos.generarDeuda(15000)
    +		
    +    // Assert
    +    assertFalse(flotaConMuchosAutos.puedeCobrarSiniestro)
    +	}
    +
    +    
    +
    +
    + +

    En el ejemplo tenemos un método helper del test que permite crear un objeto Flota pasándole la cantidad de autos a crear. De esa manera la configuración de una flota ocurre en una sola línea y se puede incluir dentro del test mismo.

    + +
    +

    Una heurística posible sobre el setup del test es tratar de mantenerlo simple y de alto nivel, más cercano al lenguaje del dominio que con detalles de implementación. En el ejemplo de arriba se logra con mensajes que se encargan de instanciar objetos de dominio y que esconden la complejidad de conocer la colaboración entre la flota y sus autos). Una alternativa a tener métodos en el test puede ser crear un objeto específico que construya otro objeto, algo que dejaremos para más adelante.

    +
    + +

    +
    +

    + +
      +
    • +

      Act: son las operaciones que tienen efecto. En el caso de la flota que tiene una deuda abultada, enviamos el mensaje que le genera la deuda. Hay tests que quizás no necesiten disparar acciones, y está bien que eso ocurra.

      +
    • +
    • +

      Assert: qué esperamos que pase, generalmente asociado a las respuestas que da el envío de un mensaje al objeto testeado.

      +
    • +
    + +

    “One assert per test”

    + +

    Hay ciertas controversias respecto a si podemos tener varios asserts en el mismo test, ya que cuando el primer assert falla los siguientes no se siguen evaluando: esto en realidad depende del runner de xUnit, podríamos eventualmente trabajar con un framework que continue buscando asserts y discrimine cuáles anduvieron y cuáles no (RSpec, framework de testeo para Ruby, hace ésto).

    + +

    En verdad, la heurística que nos interesa recomendar es: los tests deben fallar por exactamente un solo motivo, esto relaja esa restricción. Lo importante no es tener un solo assert, sino que todos los asserts estén relacionados con la misma funcionalidad. Dejamos un ejemplo concreto:

    + +
    +
    +
    +      @Test
    +@DisplayName("el parser obtiene correctamente la parte numérica de la patente del auto vieja")
    +def parsearNumerosPatenteVieja() {
    +	val lista = new PatenteParser("ABC257").parsearNumeros()
    +	assertEquals(3, lista.size)
    +	assertEquals(2, lista.get(0))
    +	assertEquals(5, lista.get(1))
    +	assertEquals(7, lista.get(2))
    +}
    +
    +    
    +
    +
    + +

    El lector puede profundizar con estos artículos:

    + + + +

    TL;DR

    + +

    Este es el resumen de buenas prácticas a la hora de definir tus tests:

    + +
      +
    • armá los escenarios que generalmente definen las clases de tests
    • +
    • utilizá anotaciones @DisplayName para la clase de test y para cada test, de manera de entender qué estamos testeando. El cómo lo terminás de ver en el código, evitá duplicidades entre el texto que explica y el código escrito
    • +
    • evitá que una clase de test tenga muchos escenarios juntos, es más difícil seguirlos
    • +
    • los nombres de las variables deben reflejar la clase de equivalencia que están resolviendo, y no casos particulares que no revelan la intención de lo que estamos modelando (sí flotaConPocosAutos, no flotinha o miFlota)
    • +
    • los tests se suelen estructurar utilizando las tres A: Arrange (el setup que conviene mantenerlo simple), Act (operaciones con efecto cuando corresponde) y Assert (las aserciones que deben testear el mismo concepto en cada test)
    • +
    + +

    Links relacionados

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/testing.html b/wiki/articles/testing.html new file mode 100644 index 0000000000..d444ea5ef5 --- /dev/null +++ b/wiki/articles/testing.html @@ -0,0 +1,461 @@ + + + + + + + + + + + Testing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Testing +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Testing en Smalltalk

    + +

    Probar una aplicación permite verificar que el sistema (o una parte de él) funciona de acuerdo a lo especificado. Los tests permiten bajar la incertidumbre y aumentar la confianza que tenemos sobre el software que desarrollamos.

    + +

    Hay diferentes formas de probar una aplicación, por ejemplo si tiene una interfaz de usuario el testeo podría realizarse manualmente siguiendo los pasos necesarios (eligiendo opciones de algún menú, llenando formularios, etc) para verificar que el sistema responde de la forma esperada. Programáticamente estamos acostumbrados a probar el sistema usando la funcionalidad desarrollada desde el mismo entorno de desarrollo, por ejemplo escribiendo en un workspace de Smalltalk. Supongamos que tenemos este ejemplo:

    + +
    +  #Golondrina
    +>> puedeVolar
    +    ^ self energia > 20
    +>> vola: unosKilometros
    +    self puedeVolar ifFalse: [ NoPuedeVolarError signal ].
    +    self energia: self energia - (unosKilometros * 2 - 8)
    +
    +pepita := Golondrina new.
    +pepita energia: 100.
    +pepita vola: 25. "Le resta 25*2+8 de energía"
    +pepita energia. "Debería retornar 42"
    +pepita puedeVolar. "Me debería decir que sí porque tiene más de 20 de energía"
    +pepita vola: 10. "Le resta 10*2+8 de energía"
    +pepita puedeVolar. "Me debería decir que no porque tiene menos de 20 de energía"
    +pepita vola: 1. "Debería explotar porque pepita no puede volar"
    +
    +
    + +

    Y al ejecutar ese workspace se puede verificar si el valor retornado por el mensaje energia luego de volar 20 kilómetros retorna el valor que esperamos que retorne, si pepita puede volar cuando tiene más de 20 de energía y que no puede cuando tiene menos, y si efectivamente ocurre un error si se intenta volar cuando pepita no puede volar.

    + +

    Sin embargo existe otra forma de realizar pruebas de forma programática que permite automatizar todo el proceso de testeo, ya que verificar que el valor de la energía de pepita sea el esperado es algo que hay que hacer manualmente. En Smalltalk vamos a usar un framework llamado SUnit (existe también para otros lenguajes con otro nombre, búsquenlo, aprovéchenlo!) que lo que permite es codificar no sólo los pasos que describen la prueba, sino también la validación de los resultados esperados.

    + +

    Automatizar las pruebas requiere un esfuerzo extra, pero es una gran inversión porque esas pruebas quedan disponibles para ser ejecutadas N veces en el futuro. A medida que el sistema crece, la cantidad de casos a probar para verificar que el sistema completo está bien construido aumenta muchísimo, y poder asegurar que toda la funcionalidad que programé ahora y que fue programada antes sigue funcionando es muy valioso.

    + +

    Testing con SUnit

    + +

    Veamos cómo quedaría el ejemplo anterior, que estaba suelto en un workspace, usando SUnit. En primer lugar, ya no va a estar suelto sino que tiene que estar en un método de una clase de prueba, para indicar que es una clase de prueba y puede ser corrida como tal por la herramienta, la misma debe heredar de TestCase.

    + +
    +  TestCase subclass: #GolondrinaTest
    +   instanceVariableNames: ''
    +   classVariableNames: ''
    +   poolDictionaries: ''
    +   category: 'Pepita-Testing'
    +
    +
    + +

    Luego podemos agregar el método para verificar que cuando pepita vuela pierde energia en función de la cantidad de kilómetros volados. Lo que nos requiere el framework es que los nombres de los métodos que yo quiera que se corran como pruebas empiecen con la palabra test, lo que nos requieren las buenas prácticas y nuestra salud mental es que el resto del nombre describa lo mejor posible qué es lo que ese método pretende testear. También es importante poder separar la lógica en unidades atómicas e independientes, de modo que cada método de test tenga un único objetivo.

    + +
    +  #GolondrinaTest >> testCuandoPepitaVuelaPierdeEnergiaEnBaseALosKilometrosVolados
    +   |pepita|
    +   pepita := Golondrina new.
    +   pepita energia: 100.
    +   pepita vola: 25.
    +   **self assert: pepita energia equals: 42.**
    +
    +
    + +

    El mensaje assert:equals: lo que hace es verificar que el resultado de una expresión sea igual a un objeto esperado.

    + +

    Si al correr este caso de prueba pepita efectivamente queda con una energía de 42, el resultado del test será correcto (lo cual se muestra con algún indicador verde que dependerá de la herramienta, como ser una bolita al lado del método).

    + +

    Si el resultado de pepita energia es otro valor, como por ejemplo 100 (porque nuestro método vola: existe pero no hace nada) el test falla, indicándose con otro color como ser amarillo, lo cual debe interpretarse como que el código se pudo ejecutar sin problemas pero el resultado obtenido fue distinto al esperado. Cuando esto sucede hay que corregir el problema que bien podría estar en el código de vola: como en el método de test porque no describe lo que realmente debería pasar, con lo cual lo que uno hace en estas situaciones por lo general es debuggear el método de test y analizar qué sucede a medida que se ejecuta el código para encontrar el problema.

    + +

    Finalmente otra cosa que podría pasar es que el código no funcione, por ejemplo si pepita no entiende el mensaje vola: se genera un error y no se puede terminar la ejecución del test, indicándose con color rojo.

    + +

    Continuemos con los casos de prueba que nos faltan. Si yo quiero testear cuándo puede volar pepita podríamos tener dos métodos diferentes, uno para verificar cuándo sí puede, y otro para verificar cuándo no.

    + +
    +  #GolondrinaTest >> testPepitaPuedeVolarSiTieneMasDe20DeEnergia
    +   |pepita|
    +   pepita := Golondrina new.
    +   pepita energia: 100.
    +   **self assert: pepita puedeVolar**
    +
    +
    + +

    El mensaje assert: recibe una expresión booleana, si esa expresión retorna true se considera correcto. Para hacer el otro caso en donde queremos validar que no pueda volar podríamos también usar assert: negando la condición (pepita puedeVolar not) o alternativamente usar el mensaje deny: que se verifica si la condición recibida es falsa.

    + +
    +  #GolondrinaTest >> testPepitaNoPuedeVolarSiTieneMenosDe20DeEnergia
    +   |pepita|
    +   pepita := Golondrina new.
    +   pepita energia: 10.
    +   **self deny: pepita puedeVolar**
    +
    +
    + +

    Por último queríamos verificar que si pepita no puede volar y le pedimos que vuele tiene que tirar un error. Si tuviéramos este código:

    + +
    +  #GolondrinaTest >> testSiPepitaDebeVolarYNoPuedeTiraError
    +   |pepita|
    +   pepita := Golondrina new.
    +   pepita energia: 10.
    +   pepita vola: 1.
    +
    +
    + +

    Cuando corramos este test, si efectivamente tira error porque no puede volar, el resultado que nos va a mostrar la herramienta será ROJO. Pero si nosotros queríamos verificar que tire error, cómo hacemos para transformar ese ROJO en VERDE?

    + +
    +  #GolondrinaTest >> testSiPepitaDebeVolarYNoPuedeTiraError
    +   |pepita|
    +   pepita := Golondrina new.
    +   pepita energia: 10.
    +   **self should: [pepita vola: 1] raise: NoPuedeVolarError**
    +
    +
    + +

    El mensaje should:raise: espera un bloque que podría tirar error al evaluarlo, y en el caso de que suceda y el error sea instancia de la clase NoPuedoVolarError (o de alguna subclase) el resultado será verde. Si el error no sucede, el resultado será amarillo para indicar que no sucedió lo que se esperaba. También existe la versión contraria shouldnt:raise: que verifica que el bloque no tire error.

    + +

    Armando un escenario

    + +

    En todos los casos anteriores lo primero que hacemos es crear la golondrina y settearle una cantidad de energía que corresponda (una con 100 para que pueda volar, otra con 10 para que no pueda). Suponiendo que por defecto vamos a querer usar una golondrina que puede volar, con lo cual tener a pepita con 100 de energía inicial, podríamos definir que antes de correr cada método de prueba de la clase GolondrinaTest hay que crear a pepita e inicializarla de esa forma. Para eso el framework nos pide que definamos un método llamado setUp de modo que todo lo que quiera que suceda antes de cada test se haga ahí, y luego sólo uso lo que se haya generado en los métodos de test.

    + +
    +  #GolondrinaTest >> setUp
    +  pepita := Golondrina new. "Nótese que pepita es una variable de instancia de la clase GolondrinaTest"
    +  pepita energia: 100.
    +
    +
    + +

    Luego podemos sólo hacer lo siguiente asumiento que pepita existe y tiene 100 de energía.

    + +
    +  #GolondrinaTest >> testPepitaPuedeVolarSiTieneMasDe20DeEnergia
    +  self assert: pepita puedeVolar
    +
    +
    + +

    Pueden ver otros ejemplos usando tanto SUnit nativo como con LOOP en este apunte: Apunte de Testing en Smalltalk (con y sin LOOP)

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/tipo-abstracto-de-datos.html b/wiki/articles/tipo-abstracto-de-datos.html new file mode 100644 index 0000000000..42c6d4a6c5 --- /dev/null +++ b/wiki/articles/tipo-abstracto-de-datos.html @@ -0,0 +1,503 @@ + + + + + + + + + + + Tipo abstracto de datos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Tipo abstracto de datos +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Concepto

    + + + +

    Implementaciones de TADs

    + +

    En C

    + +
      +
    • Definir si se lo pasará por valor o por referencia
    • +
    • Codificar el .h con las declaraciones de las funciones
    • +
    • Si usa memoria dinámica, definir una operación para la destrucción del TAD
    • +
    • Definir la estructura a emplear. Si lo hacemos en el .c o en el .h depende del grado de desacoplamiento que busquemos y nivel de paranoia que tengamos. Tambien hace mas compleja la implementación
    • +
    • Definir sinónimos de tipos para la estructura.
    • +
    • Implementar las funciones en .c
    • +
    + +

    Convenciones

    + +

    Si bien para implementar un TAD no es necesario seguir ninguna convención en particular, dado que C no tiene un soporte nativo para los mismos, y por tanto hay varias formas de implementarlos, es recomendable seguir convenciones para mantener consistencia en sus implemenentaciones y facilitar la comprensión del código a los demás programadores (o a uno mismo en el futuro). Nosotros aquí sugerimos la siguiente:

    + +
      +
    • Escribir los tipos en CamelCase. Por ejemplo AerolineaLanchita
    • +
    • Escribir las operaciones en snake_case.
    • +
    • Dado que nuestros TADs no presentarán polimorfismo (al menos no el los ejemplos básicos), las operaciones estarán prefijadas por el tipo de dato, en snake case. Esto se hará así para evitar colisiones en el espacio de nombres, y facilitar el autocompletado por parte del IDE. Por ejemplo areolinea_lanchita_comprar(char * codigo_pasaje)
    • +
    • Las operaciones privadas del TAD las declararemos y definiremos dentro del .c, prefijandolas con guión bajo, y declarandolas static
    • +
    • Respetaremos todas las buenas prácticas de programación que ya conocemos de paradigmas: delegación, expresividad, declaratividad (hasta donde podamos)
    • +
    + +

    Ejemplo: Un búffer

    + +

    Un búffer es una estructura de datos similar a una cola, diseñada para permitir el agregado de elementos o lotes de elementos homogeneos de forma eficiente, al final del mismom controlando su capacidad y taza de expansión para reducir al mínimo las operaciones de gestión de memoria. A diferencia de una cola, los elementos del buffer no se sacan de a uno, sino que se extraen también en lotes. Buffers más avanzados soportan también punteros internos para delimitar regiones dentro del mismo.

    + +

    Por sus características, los buffers son usados típicamente para almacenar bytes o caracteres.

    + +

    Modelaremos un buffer de caracteres. Este soportará las siguientes operaciones:

    + +
      +
    • Creación: se creará con un tamaño inicial fijado por el usuario
    • +
    • Concatenación: ofrecerá una operación para agregar un solo caracter, y otra para agregar un conjunto de caracteres.
    • +
    • Extracción: expondrá una operación para extraer todos los caracteres como un char*. Una vez devuelto, es importante que el buffer pierda toda referencia al array original
    • +
    • Destrucción: expondrá una operación para destruir el buffer. Es importante que libere no solo la memoria usada por el buffer, sino también, la memoria del contenido del mismo, si no fue ya devuelto.
    • +
    + +

    Declaración de las operaciones

    + +

    Pensar las operaciones no se trata tan solo de pensar que funcionalidad expondrá, sino también, y en particular cuando tenemos TADs con estado mutable, pensar cuales son las precondiciones y postcondiciones de las mismas, y las invariantes del TAD.

    + +

    Esta no es solo una buena práctica de diseño estructurado, sino que puede ser muy beneficiosa a la hora de trabajar en cualquier paradigma. Es decir, para especificar correctamente una operación no basta con indicar su firma/tipo y su semántica, sino también sus restricciones operacionales.

    + +

    Estas declaraciones las colocaremos en un .h

    + +
    +  Buffer * buffer_new(int max_size);
    +void buffer_append_char(Buffer * self, char aChar);
    +void buffer_append_chars(Buffer * self, char * chars, int count);
    +char * buffer_extract(Buffer * self);
    +int  buffer_current_size(Buffer * self);
    +void buffer_delete(Buffer ** self);
    +
    +
    + +

    Definición de la estructura interna

    + +

    + Para mas detalles sobre la sintaxis, ver Typedefs y tipos anónimos +

    + +

    Para modelar la estructura interna del buffer, utilizaremos un struct, que tendrá un campo por cada atributo de nuestro TAD: contenido, tamaño máximo y tamaño actual.

    + +
    +  typedef struct {
    +  char * content;
    +  int current_size;
    +  int max_size;
    +} Buffer;
    +
    +
    + +

    Definición de las operaciones

    + +

    + Para mas detalles sobre las funciones de manejo de memoria, ver Manejo de memoria en C +

    + +

    La primera operación que debemos soportar es la instanciación del TAD. Esta operación debe tomar un tamaño máximo inicial, y reservar la memoria necesaria para el buffer en sí mismo, y el vector de memoria donde se copiarán los contenidos. También debe inicializar los atributos del TAD.

    + +

    Por convención y analogía con objetos, llamaremos a esta operación new:

    + +
    +  Buffer * buffer_new(int max_size) {
    +  Buffer * self = instance_new(Buffer);
    +  self->content = instance_new_array(char, max_size);
    +  self->current_size = 0;
    +  self->max_size = max_size;
    +  return self;
    +}
    +
    +
    + +

    La contrapartida de la instanciación del TAD es la destrucción del mismo. En ambientes con Garbage Collector esto no es normalmente necesario, por lo que no existe operación análoga en objetos. Por convención, la llamaremos delete:

    + +
    +  void buffer_delete(Buffer ** self) {
    +  if( (*self)->content != NULL ) {
    +    instance_delete((*self)->content);
    +  }
    +  instance_delete(*self);
    +}
    +
    +
    + +

    Nótese que esta operación toma como argumento una doble indirección a un Buffer.

    + +

    En este caso particular, el enunciado nos plantea que solo se debe liberar la memoria del contenido del buffer, si y solo si no se ha devuelto el contenido al usuario del TAD. Para resolver esto, señalizaremos un contenido entregado al usuario setéandolo en NULL.

    + +

    Esto mismo debemos considerarlo a la hora de justamente devolver ese contenido, mediante la operación extract. Para cumplir con la precondición de que el contenido no ha sido devuelto antes, agregaremos una aserción:

    + +
    +  char * buffer_extract(Buffer * self) {
    +  assert(self->content != NULL);
    +  buffer_append_char(self, '\0');
    +  char * content = self->content;
    +  self->content = NULL;
    +  return content;
    +}
    +
    +
    + +

    Luego tenemos que encarar el problema de agregar caracteres. Llamaremos a esta operación ‘apend_chars, que tomará como parámetro el vector de caracteres a copiar, y su longitud.

    + +

    La operación no es trivial: debemos considerar que si no hay suficiente espacio en el buffer (es decir, la diferencia entre el tamaño actual y el máximo es menor a la longitud del vector), deberemos redimesionar el buffer de forma eficiente.

    + +

    Sin embargo, aún así podemos comenzar a atacar el problema, delegando apropiadamente:

    + +
    +  void buffer_append_chars(Buffer * self, char * chars, int count){
    +  _buffer_expand(self, count);
    +  memcpy(self->content + self->current_size, chars, count);
    +  self->current_size += count;
    +}
    +
    +
    + +

    Es decir, decimos que para copiar un vector de caracteres al final del buffer, debemos expandir nuestro buffer tanto como sea necesario para almacenar los caracteres, y luego procedemos a efectivamente realizar la copia y actualizar el tamaño actual. Ahora, tenemos un problema un poco mas simple: solo debemos preocuparnos por redimensionar el buffer, de ser necesario.

    + +

    Dado que _buffer_expand no será usada desde el exterior (es una operación interna), no la colocamos en nuestro .h.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/tipos-de-haskell.html b/wiki/articles/tipos-de-haskell.html new file mode 100644 index 0000000000..2f23e176dd --- /dev/null +++ b/wiki/articles/tipos-de-haskell.html @@ -0,0 +1,585 @@ + + + + + + + + + + + Tipos de haskell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Tipos de haskell +

    +
    + + + +
    +

    Tal vez convenga aclarar que esta no es una categorización teórica, es más bien una introducción y vamos de lo más simple a lo más complejo.

    + +

    Tipos Simples

    + +

    Los tipos más básicos que tenemos en Haskell son los booleanos y los caracteres, que tiene los tipos y respectivamente:

    + +
    Prelude> :t True
    +True :: Bool
    +Prelude> :t 'a'
    +'a' :: Char
    +
    + +

    Qué podemos hacer con ellos? Algunos ejemplos con booleanos y caracteres:

    + +
    Prelude> True && False
    +False
    +Prelude> True || False
    +True
    +Prelude> not True
    +False
    +
    +Prelude> Char.isLower 'a'
    +True
    +Prelude> Char.isUpper 'a'
    +False
    +Prelude> Char.toLower 'A'
    +'a'
    +Prelude> Char.toUpper 'a'
    +'A'
    +Prelude> 'b' > 'a'
    +True
    +
    + +

    El tipo de los números es un poquito más complejo porque tenemos números enteros, reales, racionales y muchas más variantes, lo vamos a ver en más detalle más adelante. Algunas operaciones que podemos hacer:

    + +
    Prelude> 4*6
    +24
    +Prelude> 2+3
    +5
    +Prelude> 9-4
    +5
    +Prelude> 4 `div` 3 
    +1
    +Prelude> 4 `mod` 3 
    +1
    +Prelude> 4/6
    +0.6666666666666666
    +
    + +

    La división en ocasiones puede traer problemas de tipos, si tuviste problemas con esto leé el siguiente artículo

    + +

    Tipos Compuestos

    + +

    Listas y Strings

    + +

    Un String es simplemente una lista de caracteres que puede escribirse con una sintaxis particular, los siguientes ejemplos son equivalentes:

    + +
    Prelude> :t "Hola"
    +"Hola" :: [Char]
    +Prelude> :t ['H','o','l','a']
    +['H','o','l','a'] :: [Char]
    +
    + +

    Para cualquier lista el tipo se escribe poniendo entre corchetes el tipo de los elementos la lista, por ejemplo una lista de booleanos:

    + +
    Prelude> :t [True, False]
    +[True, False] :: [Bool]
    +
    + +

    También una lista de Strings (o lista de listas de caracteres):

    + +
    Prelude> :t ["Hola", "Chau"]
    +["Hola", "Chau"] :: [ [Char] ]
    +
    + +

    Tuplas

    + +

    Una tupla es también un valor compuesto. A diferencia de las listas el número de componentes es fijo y los componentes pueden ser cada uno de un tipo distinto. (Esto está más detallado en ¿Cuál es la diferencia entre una tupla y una lista?, pero antes te recomiendo mirar los ejemplos que siguen.)

    + +

    Una de las tuplas más simples que se puede imaginar es:

    + +
    Prelude> :t (True, 'H')
    +(True, 'H') :: (Bool, Char)
    +
    + +

    es decir, una tupla compuesta por un booleano y un caracter. Sin embargo, los elementos de las tuplas también pueden ser compuestos, como un String:

    + +
    Prelude> :t (True, "Hola")
    +(True, "Hola") :: (Bool, [Char])
    +
    + +

    o inclusive el componente de una tupla puede ser otra tupla:

    + +
    Prelude> :t (False, ('H', "ola"))
    +(False, ('H', "ola")) :: (Bool, (Char, [Char]))
    +
    + +

    También podemos tener tuplas de más de dos componentes

    + +
    Prelude> :t (True, 'H', [False])
    +(True, 'H', [False]) :: (Bool, Char, [Bool])
    +
    + +

    es decir, un booleano, un caracter y una lista de booleanos.

    + +

    Para finalizar podemos ver un ejemplo en el que combianmos todo lo anterior (no es trivial, tomate tu tiempo para leerlo!):

    + +
    Prelude> :t ([True, False, True], "Chau", [(True, "True"), (False, "False")])
    +([True, False, True], "Chau", [(True, "True"), (False, "False")])
    +  :: ([Bool], [Char], [(Bool, [Char])])
    +
    + +

    Es decir, una tupla de tres componentes, a saber:

    + +
      +
    • Una lista de booleanos
    • +
    • Un string o lista de caracteres
    • +
    • Una lista de tuplas cuyo primer componente es un booleano y su segundo componente es un string.
    • +
    + +

    Type

    + +

    Haskell nos permite definir sinónimos de tipos, o sea definir un alias para un tipo concreto que se use para modelar alguna abstracción que nos interese.

    + +

    Por ejemplo si modelamos a los alumnos como tuplas de aridad 2 cuyo primer elemento es el nombre y el segundo una lista de números que representa las notas que se sacó, podríamos definir un tipo Alumno como:

    + +
    type Alumno = (String, [Int])
    +
    + +

    De hecho, String no es más que un alias para el tipo [Char]. Sin embargo, es importante tener en cuenta que estos sinónimos sólo son útiles a efectos de declarar los tipos de otros datos o de las funciones de nuestro programa, pero para el motor de inferencia de tipos, estos alias son ignorados con lo cual si preguntamos de qué tipo es una función en donde se espera un alumno por parámetro, nos dirá (String, [Int]) y no Alumno.

    + +

    Data

    + +

    Es posible definir nuestros propios tipos de dato usando data para poder mejorar las abstracciones de nuestros programas y evitar algunos problemas asociados al uso de tuplas. Esto puede hacerse de la siguiente forma:

    + +
    data NuevoTipo = Constructor Tipo1 Tipo2 ... TipoN
    +
    + +

    Usamos el constructor, como su nombre lo indica, para construir nuestros datos de este tipo y para hacer pattern matching como hacíamos con las tuplas.

    + +
    data Alumno = UnAlumno String [Int]
    +fede = UnAlumno "Federico" [2,3]
    +nombreAlumno (UnAlumno nombre notas) = nombre
    +> :t nombreAlumno
    +nombreAlumno :: Alumno -> String
    +> nombreAlumno fede
    +"Federico"
    +
    + +

    El nombre del constructor puede coincidir con el nombre del tipo de dato, en este caso usamos nombres distintos para denotar que son cosas distintas y en qué contexto se usa cada una.

    + +

    Funciones

    + +

    Funciones con un único parámetro

    + +

    El tipo de una función que tiene un parámetro se indica relacionando mediante el símbolo la entrada o dominio de la función con la salida o imagen. Por ejemplo la función not recibe un booleano y devuelve otro:

    + +
    Prelude> :t not
    +not :: Bool -> Bool
    +
    + +

    La función isLower recibe un caracter y devuelve un booleano.

    + +
    Prelude> :t isLower 
    +isLower :: Char -> Bool
    +
    + +

    (Nótese que la función isLower está en el módulo Char, dependiendo de su versión de Haskell tal vez deban escribir para poder probar el ejemplo, o bien importar el módulo correspondiente.)

    + +

    Y la función and recibe una lista de booleanos y devuelve un booleano (resultado de realizar la conjunción entre todos los booleanos de la lista)

    + +
    Prelude> :t and
    +and :: [Bool] -> Bool
    +
    + +

    Funciones con más de un parámetro

    + +

    Las funciones de más de un parámetro tienen alguna sutileza porque en Haskell se trabaja con el concepto de Currificación, entonces una función que nosotros en matemática estaríamos acostumbrados a verla como en Haskell la vamos a escribir . Las funciones de dos parámetros cuyo tipo tiene esa forma se denominan currificadas.

    + +

    (A los efectos de entender el sistema de tipos podemos pensarlo simplemente como una función que recibe dos booleanos, aunque en realidad la versión currificada es mucho más poderosa. Para más detalles ver la teoría sobre Currificación.)

    + +

    El tipo que usamos como ejemplo en el párrafo anterior corresponde (entre otros) a la función

    + +
    Prelude> :t (&&)
    +(&&) :: Bool -> Bool -> Bool
    +
    + +

    Aplicación

    + +

    La aplicación es uno de los temas que tal vez más confunden cuando se habla de tipos de datos. La confusión más frecuente radica en no diferenciar correctamente una expresión que tiene valor Booleano de una función que devuelve Booleanos.

    + +

    Ya vimos dos ejemplos de funciones que devuelven booleanos, con uno y dos parámetros:

    + +
    Prelude> :t not
    +not :: Bool -> Bool
    +Prelude> :t Char.isLower
    +Char.isLower :: Char -> Bool
    +Prelude> :t and
    +and :: [Bool] -> Bool
    +Prelude> :t (&&)
    +(&&) :: Bool -> Bool -> Bool
    +
    + +

    En este punto es importante entender que ninguno de estos ejemplos es un valor booleano. Cuando veo el tipo eso se entiende como el tipo de las funciones a las que si les aplico un parámetro de tipo Char producen un valor de tipo Bool, que claramente no es lo mismo que el tipo Bool.

    + +

    Lo dicho, si le aplicamos los parámetros adecuados a esas funciones, podemos obtener valores booleanos:

    + +
    *Main> :t not True
    +not True :: Bool
    +*Main> :t Char.isLower 'a'
    +Char.isLower 'a' :: Bool
    +*Main> :t and [True, False, True]
    +and [True, False, True] :: Bool
    +*Main> :t True && False
    +True && False :: Bool
    +
    + +

    En síntesis es un valor booleano, en cambio no es un valor booleano, es una función que devuelve booleanos. También es un valor, pero es un valor de otro tipo y no se pueden mezclar.

    + +

    Si intentamos utilizar un valor función en un lugar donde se espera un valor booleano, obtendremos un error:

    + +
    *Main> not Char.isLower
    +<interactive>:1:4:
    +     Couldn't match expected type `Bool' 
    +            against inferred type `Char -> Bool' 
    +     In the first argument of `not' ... 
    +
    + +

    Es decir, el primer argumento de debe ser y en cambio se recibió un argumento de tipo .

    + +

    Similarmente:

    + +
    *Main> True && not
    +<interactive>:1:8:
    +     Couldn't match expected type `Bool' 
    +            against inferred type `Bool -> Bool' 
    +    In the second argument of `(&&)', namely `not' 
    +    In the expression: True && not
    +    ....
    +
    + +

    Typeclasses

    + +

    Si en algún momento consultaste el tipo de una función y viste algo como: Num a => ..., Ord a => ... o Eq a => ..., significa que esa función puede trabajar con distintos tipos concretos (como ser Int o Float). Num, Ord y Eq (al igual que otras menos cotidianas) no son tipos, sino familias de tipos que imponen restricciones sobre qué valores pueden usarse para evaluar esa función. A las familias de tipos les vamos a llamar Typeclasses.

    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/tipos-de-mensajes-en-smalltalk.html b/wiki/articles/tipos-de-mensajes-en-smalltalk.html new file mode 100644 index 0000000000..94a87160d7 --- /dev/null +++ b/wiki/articles/tipos-de-mensajes-en-smalltalk.html @@ -0,0 +1,352 @@ + + + + + + + + + + + Tipos de mensajes en smalltalk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Tipos de mensajes en smalltalk +

    +
    + + + +
    +

    Primero arranquemos por lo básico. Todo envío de mensaje sigue la siguiente regla: OBJETO MENSAJE PARAMETRO Lo primero que aparece es el objeto receptor, luego viene el mensaje que se le envía a dicho objeto el cual puede o no tener parámetros.

    + +

    Smalltalk es bastante particular en aspectos sintácticos, por eso es importante detenerse a entender cómo se interpreta. Hay 3 tipos de mensajes en Smalltalk.

    + +

    Los mensajes unarios son aquellos que no reciben parámetros, o sea que el receptor solito puede resolver lo pedido. Un ejemplo de esto sería la negación de un booleano:

    + +

     true not +   --> retorna false

    + +

    También existen los mensajes binarios que son los que reciben sólo un parámetro y su nombre está compuesto por símbolos (no alfanumérico), por ejemplo la suma entre dos números es un mensaje que recibe un parámetro solo (el número a sumar), el otro número es el receptor del mensaje.

    + +

     2 + 5 +   --> retorna 7

    + +

    Por último están los mensajes de palabra clave que pueden recibir tantos parámetros como sean necesarios. Estos mensajes se caracterizan por tener una o más partes alfanuméricas terminadas por el caracter : luego de los cuales se pasa cada parámetro (o sea, los parámetros van intercalados) como se muestra en los siguientes ejemplos:

    + +

     5 raisedTo: 2 +   --> es un mensaje que recibe el objeto 5 con un único parámetro, el 2, y retorna 25

    + +

     3 between: 10 and: 25 +   --> es un mensaje que recibe el objeto 3 con un 2 parámetros, el 10 es el primer parámetro y el 25 es el segundo, y retorna false

    + +

    Lo que tiene de simpático los parámetros intercalados es la expresividad, pero hay que ser cuidadosos de no cometer errores. Por ejemplo si quisiéramos saber si el 3 está entre 10 y el 5 elevado al cuadrado debemos escribirlo de esta forma:

    + +

     3 between: 10 and: (5 raisedTo: 2) +   --> el segundo parámetro del mensaje between:and: es el resultado de mandarle raisedTo: a 5 con el parámetro 2, lógicamente también retorna false

    + +

    Esos paréntesis son inportantes para que se interprete como queremos y no como un único envío de mensajes, donde el mensaje sería between:and:raisedTo: de 3 parámetros, que los números no entienden!

    + +

    La Precedencia de Mensajes en Smalltalk se basa en estos 3 tipos de mensajes, sólo nos va a interesar esta diferenciación por ese motivo.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/tips-para-aprobar-un-parcial-de-funcional.html b/wiki/articles/tips-para-aprobar-un-parcial-de-funcional.html new file mode 100644 index 0000000000..86371ca5fe --- /dev/null +++ b/wiki/articles/tips-para-aprobar-un-parcial-de-funcional.html @@ -0,0 +1,327 @@ + + + + + + + + + + + Tips para aprobar un parcial de funcional + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Tips para aprobar un parcial de funcional +

    +
    + + + +
    +

    Lo que tiene que estar seguro para aprobar el parcial de funcional es Orden Superior, Aplicación Parcial y Composición.

    + +

    Algunas consideraciones que te llevan para el lado de la aprobación:

    + +

    -Entender que cuando se aplica una función parcialmente lo que se obtiene es otra función con n - m parámetros (siendo n los parámetros de tu función original y m los que le aplicaste).

    + +

    -Entender bien la diferencia entre aplicar funciones y componer funciones entre sí (nunca intentar componer cosas que no sean funciones o que al no estar suficientemente aplicadas esperen más de un parámetro)

    + +

    -Usar buenas abstracciones tanto propias (defininiendo funciones auxiliares que ayuden a dividir el problema el problemas más chicos) como existentes, por ejemplo en vez de hacer una función recursiva para trabajar con una lista usar funciones como filter, map, all, any o algún fold que se adecúe al problema

    + +

    -Pensar en los tipos de las cosas que reciben y retornan las funciones para asegurarte de que lo que estás haciendo tiene sentido. Si te cuesta el proceso de inferir el tipo de una función acá hay un ejemplito que está bueno para entender cómo se hace: Cálculo del tipo de una función en Haskell#Ejemplo un poco mas heavy

    + +

    Es importante no cometer errores de los que aparecen acá: Errores comunes al comenzar a trabajar con Haskell. Estos errores vienen de la mano de no tener claros los conceptos de orden superior, aplicación parcial y composición, con lo cual se consideran invalidantes.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/tips-para-concursos-docentes.html b/wiki/articles/tips-para-concursos-docentes.html new file mode 100644 index 0000000000..b1348d490a --- /dev/null +++ b/wiki/articles/tips-para-concursos-docentes.html @@ -0,0 +1,347 @@ + + + + + + + + + + + Tips para concursos docentes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Tips para concursos docentes +

    +
    + + + +
    +

    Para un concurso hay varios consejos importantes a tener en cuenta:

    + +
      +
    • tenés que dar una clase como si estuvieras ante estudiantes. O
    • +
    + +

    sea, olvidate que hay un jurado, y hablá como si hubiera estudiantes. Un error común es hablarle al jurado y decir “acá haría tal cosa”, o más común, saltarse partes y decir “acá explicaría que esto y esto” en lugar de explicarlas. Da una clase como si hubiera estudiantes y nada más. Otro error común (y que a veces lo hacemos en clase también, pero acá es mortal) es pasar transparencias rápido y decir “esto no importa”… Si no importa, no lo pongas!!!!!

    + +
      +
    • antes de la clase, explicá el contexto de la misma. O sea, qué
    • +
    + +

    materias hay antes y después en el plan, qué clases se dieron en esta materia antes que la que vas a dar, y todos los conocimientos que los estudiantes se supone que tienen para que vos des la clase. Explicá los objetivos de la materia y de la clase, y cómo tu clase contribuye a los objetivos de la materia. Eso muestra que estás ubicado y que conocés de lo que hablás y es muy valorado por los jurados. Pero esto antes de empezar tu clase. Durante la clase, aplica 1.

    + +
      +
    • prepará una clase como para 45 minutos, y está listo para darla
    • +
    + +

    completa. Lo más probable es que el jurado te corte antes y te diga “listo, gracias” y ahí cortá y punto. O te dicen “saltá hasta las conclusiones” y ahí vos saltás cosas. Tenés que tener flexibilidad para hacer fast forward cuando te lo piden, pero siempre acordándote de 1 (o sea, es fastForward o saltear cosas, NO cambiar de modo a “y acá haría tal y cual”).

    + +
      +
    • El manejo del tiempo es escencial. Si te hacen ir hasta el
    • +
    + +

    final, que sean 45 minutos y no más o menos! Además, lo ideal es que tengas un recorrido de tu clase para 30 minutos (o sea, 15 minutos de material que no es 100% escencial, pero que contribuye). De esa manera, si al empezar te dicen “tenés media hora”, no tenés que correr con tus 45 comprimidos, y lo hacés eliminando este material. Tené en cuenta que visto el consejo 1., tendrías que tener 2 cosas preparadas… :)

    + +
      +
    • Pensá bien el uso de recursos y materiales de tu clase. Vas a
    • +
    + +

    usar transparencias? Pizarrón? Combinación de ambos? El pizarrón, es de tiza o de fibrones? No asumas. Lo ideal es que tengas con vos borrador y fibrones (cargados) – normalmente si es tiza, hay, pero los fibrones suelen estar chotos. Si usás transparencias, hay que avisar a concursos, y ellos te llevan el cañón. Pero si estás preparado para que eso no pase, mejor (en TPI tenemos cañones y alguien siempre te puede alcanzar uno si avisás!) También tenés que estar listo para que se corte la luz y no haya cañón! Lo mejor para esto es tener las transparencias impresas, y repartir una copia. Es un backup muy de emergencia, pero paga. Incluso podés repartir las transparencias impresas igual, aunque puede sonar a sobreactuación…

    + +
      +
    • Cuando uses el pizarrón, administralo. Si llenás el pizarrón de
    • +
    + +

    cosas inútiles, nunca lo borrás y escribís en agujeritos, es malísimo! Yo suelo tener una franja en un costado donde voy dejando “la traza” de la clase, como para que los alumnos sepan siempre dónde estamos. Y el resto lo divido en cosas más fijas y en espacio para ejemplos (este último se borra más seguido). Hacé buena letra en el pizarrón (esforzate!!!!! :)) y no des vueltas. La mejor combinación es usar transparencias y pizarrón, administrando cada una. Pero cada profe sabe cómo lo hace mejor… :)

    + +
      +
    • Respecto a la preparación de la clase en sí, tené siempre claro
    • +
    + +

    cuál es el objetivo de la misma. Todo se arma en función de esto. Los ejemplos se eligen porque ilustran un concepto que contribuye al objetivo. No pongas ejemplos de más o boludeces adicionales que no contribuyen al objetivo (a menos que el objetivo de la clase sea dar un potpurrí de “boludeces”! :D). Cada transparencia debe contribuir de manera interesante al objetivo. Si armás transparencias, que haya una de título, una de overview y una de conclusiones, para estructurar la clase. Que en cada transparencia quede claro de qué se habla (con un buen título).

    + +
      +
    • Si tenés que hacer alguna demo de soft o algo así, tené todo
    • +
    + +

    probado y listo! Lo ideal en estos casos es llevar tu propia compu con todo andando. No confíes en las compus que puedan estar en el aula tengan todo configurado como vos esperás. Si no tenés compu y dependés de lo que haya, entonces tratá de tener una versión portable del soft, o si esto no se puede, tener un videíto de lo que querés mostrar o similar… Es importante no mostrar que uno pierde media hora tratando de que un ejemplo ande.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/tips-para-la-resolucion-de-un-parcial-de-tadp.html b/wiki/articles/tips-para-la-resolucion-de-un-parcial-de-tadp.html new file mode 100644 index 0000000000..ba1cef07c7 --- /dev/null +++ b/wiki/articles/tips-para-la-resolucion-de-un-parcial-de-tadp.html @@ -0,0 +1,352 @@ + + + + + + + + + + + Tips para la resolucion de un parcial de tadp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Tips para la resolucion de un parcial de tadp +

    +
    + + + +
    +

    Herramientas a utilizar (o cosas que no pueden faltar)

    + +
      +
    • Un diagrama de clases (que muestre una visión panorámica del sistema)
    • +
    • Código (en el que se ven los detalles)
    • +
    • +

      Especificación de interfaces +Interfaces entrantes: Indicar cuáles son todas las cosas que se le pueden pedir al sistema desde afuera y para cada uno de estos posibles pedidos especificar qué mensaje debe llegarle a qué objeto para que el sistema lleve a cabo la funcionalidad deseada. +Interfaces salientes: Definir una interfaz Java para cada una de ellas e indicar la forma en que un objeto externo que implmente esa interfaz se puede registrar en el sistema para comenzar a interactuar con él.

      +
    • +
    • Diagramas adicionales +
        +
      • Si en alguna funcionalidad intervienen muchos objetos u ocurre una cadena larga de delegaciones, es interesante mostrar una visión global de la misma en un diagrama de secuencia o de colaboración.
      • +
      • Si un objeto o una parte del sistema pasa por varios estados diferentes puede ser interesante hacer un diagrama de estados.
      • +
      +
    • +
    + +

    : Es importante destacar que el diagrama no reemplaza al código. El diagrama provee una visión de alto nivel de la solución, para que quien tiene que leerlo tenga un primer pantallazo de la estrategia utilizada; luego es necesario bajar a los detalles y para eso es necesario verlos en el código.

    + +
      +
    • Aclaraciones adicionales que puede ser útil incluir +
        +
      • Justificar las decisiones, contando las alternativas que se tuvieron en cuenta y la motivación para elección realizada.
      • +
      • Potenciales puntos débiles detectados en la solución propuesta; junto con la justificación de por qué se propone esta solución a pesar de esas dificultades señaladas.
      • +
      • Cualquier otro comentario que ayude a comprender la solución propuesta.
      • +
      +
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/traits.html b/wiki/articles/traits.html new file mode 100644 index 0000000000..81d95a860c --- /dev/null +++ b/wiki/articles/traits.html @@ -0,0 +1,393 @@ + + + + + + + + + + + Traits + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Traits +

    +
    + + + +
    +

    Un trait permite definir un conjunto de métodos que se pueden aplicar a cualquier clase, de modo que se puedan evitar los problemas asociados a la herencia múltiple en relación a la solución de conflictos.

    + +

    Características

    + +

    En su definición, el conocimiento colectivo asocia a los traits con las siguientes caracteristicas:

    + +
      +
    • Proveen un conjunto de métodos que implementan comportamiento.
    • +
    • Pueden requerir que el usuario provea un conjunto de métodos “requeridos” para su funcionamiento.
    • +
    • No pueden ser instanciados directamente.
    • +
    • No permiten definir estado interno de ninguna naturaleza.
    • +
    • No pueden acceder de forma directa al estado interno definido por el usuario.
    • +
    • Pueden ser compuestos entre ellos para generar un nuevo Trait.
    • +
    • La composición de Traits es simétrica, asociativa y conmutativa y cualquier método conflictivo es excluido de su resultado.
    • +
    • Se espera que el lenguaje provea algún mecanismo para realizar la resolución de conflictos.
    • +
    • Se resuelven por aplanamiento o flattening.
    • +
    + +

    Sin embargo, a diferencia de las Clases (concepto que ha sido trasladado a varios lenguajes), el termino Trait es usado en varias tecnologías para referirse a construcciones similares, caracterizadas por un subconjunto de estas propiedades, lo cual vuelve borroso el concepto y hace difícil definir que puede o no esperarse de un Trait. Por ese motivo tomamos como implementación de referencia a la que se encuentra en Smalltalk, desarrollada en base al paper Traits: Composable Units of Behaviour.

    + +

    Álgebra de Traits

    + +

    A continuación se detallan las operaciones que se encuentran implementadas en Smalltalk para usar traits:

    + +

    +: Combina dos Traits en uno nuevo, el cual contiene todas las implementaciones definidas en ambos Traits.

    + +

    -: Genera una copia del Trait destino, quitando la implementación del mensaje recibido por parámetro.

    + +

    @: Realiza una copia de la implementación de un mensaje, utilizando otro nombre.

    + +

    + +

    Solución de conflictos

    + +

    En aquellos casos en los que una clase usa dos traits que presentan implementaciones diferentes del mismo mensaje, se produce un conflicto, que debe ser resuelto en la definición de la clase en cuestión, de lo contrario si una instancia de la misma recibe este mensaje ocurrirá un error por el conflicto sin resolver.

    + +

    Las herramientas provistas por el lenguaje para la resolución de conflictos se basa en las operaciones - y @ definidas anteriormente y en la premisa de que si se define el mismo mensaje en la clase o trait en conflicto, esta definición tendrá mayor peso, con lo cual las otras definiciones dejan de usarse y el conflicto desaparece.

    + +

    Por ejemplo, si la clase A usa a los traits B y C, y tanto B como C definen #m algunas posibilidades para resolver el conflicto de #A>>m son:

    + +
      +
    • Restarle a uno de los traits el mensaje #m, con lo cual sólo existirá una implementación, por ejemplo:
    • +
    + +

    Object subclass: #A +       uses: B - #m + C +       ...

    + +
      +
    • Definir la implementación real para A usando un alias para los métodos de traits, por ejemplo:
    • +
    + +

    Object subclass: #A +       uses: B @#{#mDeB -> #m} + C @#{#mDeC -> #m} +       ...

    + +

    y luego…

    + +

    #A>>m +  self mDeB. +  self mDeC.

    + +

    Si no se define #A>>m además de definir los alias, el conflicto sigue existiendo.

    + +

    ¿Cómo diseñamos con Traits?

    + +

    Algunas teorías dicen que todo el comportamiento debería estar en los Traits (ver paper de Ducasse citado), según esas ideas una clase se define como:

    + +

    Superclase + Trait composition (conjunción de varios traits) + Estado + Glue code 

    + +

    Por otro lado existe el enfoque opuesto de modo que los Traits sólo se usan como parches para el modelo con herencia simple de modo que se eviten las repeticiones de código. Si sólo se busca extraer el código repetido, el Trait extraído podría no tener consistencia semántica y no conformar una entidad representativa, volviéndose difícil de reutilizar y generando abstracciones pobres.

    + +

    No hay ideas muy formadas aún sobre cómo diseñar con traits y herencia simple dándoles igual peso a ambas herramientas, por lo tanto en principio, seguir el primer enfoque y a partir de ello poder descubrir mejores alternativas es una estrategia interesante para el aprendizaje.

    + +

    Traits y super

    + +

    La meta-variable super se usa para modificar el Method Lookup de modo que sea posible redefinir métodos heredados y a su vez reutilizar la definición de la Clase padre.

    + +

    El uso de super en un método de Trait es técnicamente posible ya que estos métodos serán invocados en el contexto de las Clases usuarias donde existe una superclase de la cual se heredan definiciones de métodos. Sin embargo esto implica que el Trait sólo pueda ser usado en contextos en los cuales la superclase tenga una implementación del mensaje enviado en el método de Trait, quedando altamente acoplado con los usuarios del mismo y por lo tanto disminuyendo su reutilizabilidad.

    + +

    Papers

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/transparencia-referencial--efecto-de-lado-y-asignacion-destructiva.html b/wiki/articles/transparencia-referencial--efecto-de-lado-y-asignacion-destructiva.html new file mode 100644 index 0000000000..4dee9ff8b4 --- /dev/null +++ b/wiki/articles/transparencia-referencial--efecto-de-lado-y-asignacion-destructiva.html @@ -0,0 +1,487 @@ + + + + + + + + + + + Transparencia referencial efecto de lado y asignacion destructiva + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Transparencia referencial efecto de lado y asignacion destructiva +

    +
    + + + +
    +

    Definiciones

    + +

    Operación: aplicar una función, evaluar un predicado, enviar un mensaje, etc.

    + +

    Transparencia Referencial

    + +

    Hay transparencia referencial si al reemplazar una operación por su resultado se logra el mismo efecto.

    + +

    Una definición alternativa dice: Hay transparencia referencial cuando al realizar una operación con los mismos valores siempre da el mismo resultado. Si bien esta parece más fácil de entender, no es tan precisa como la primera; puede ser útil para dar los primeros pasos, pero para el final hay que terminar de entender la otra.

    + +

    También se puede pensar en las propiedades necesarias para tener Transparencia Referencial.

    + +

    Decimos que una operación tiene transparencia referencial si es:

    +
      +
    • Independiente: No dependen del estado de nada que este fuera de sí misma
    • +
    • Sin estado/Stateless: No tiene un estado que se mantenga de llamada en llamada
    • +
    • Determinística: Siempre devuelven el mismo valor dados los mismos argumentos
    • +
    • No produce efecto colateral
    • +
    + +

    Efecto de Lado/Colateral (Side Effect)

    + +

    Hay efecto cuando un cambio de estado sobrevive a la realización de una operación. Por ejemplo, una operación puede modificar una variable global, modificar uno de sus argumentos, escribir datos a la pantalla o a un archivo, o hacer uso de otras operaciones que tienen efecto de lado.

    + +

    Otra definición válida es: Si le sacás una foto al sistema (llamémosla F1), después realizas la operación de tu interés, y le volvés a sacar una foto al sistema (F2). Si F1 y F2 son distintas => la operación que hiciste tiene efecto de lado.

    + +

    Asignación Destructiva

    + +

    Asignar destructivamente es reemplazar el valor de una variable por otro valor.

    + +

    La unificación no se considera asignación (al momento de ligar no había ningún valor anterior, ¿sería más bien una inicialización?). Unificar es encontrar una sustitución capaz de igualar 2 términos. Cuando se efectiviza está sustitución hablamos de ligado de variables (tal valor se ligó a tal variable).

    + +

    Ejemplos

    + +

    Cuando hablamos de que “algo” tiene transparencia referencial, efecto colateral o asignación destructiva, ese “algo” es la realización de una operación, de un lenguaje en particular o de un paradigma.

    + +

    Estos tres conceptos suelen ir de la mano y si bien pueden darse relaciones entre ellas es saludable poder detectar la aparición de cada uno de ellos individualmente. Una relación que surge de la definición de transparencia referencial es que para ésta se dé, no puede haber efecto colateral, ya que si el estado del sistema se modifica, o se escribe en un archivo por ejemplo, no es lo mismo ejecutar esa operación que reemplazar por el resultado.

    + +

    A continuación mostramos algunos ejemplos en el paradigma orientado a objetos, ya que permite la aparición de todas estas características, para dejar más en claro de qué manera podemos identificarlas.

    + +

    Ejemplo 1: consulta no determinística

    + +

    El siguiente código crea una fecha, configurada para representar el día de hoy: new Date()

    + +
      +
    • Transparencia Referencial: NO (Con cualquiera de las 2 definiciones de transparencia referencial)
    • +
    • Efecto: NO
    • +
    • Asignación Destructiva: NO
    • +
    + +

    Evaluarlo con los mismos parámetros (o sea ninguno) en días distintos va a dar resultados distintos. Reemplazar la operación por el resultado una vez que cambia el día se rompe todo. Asignación destructiva y efecto no hay, o al menos no es relevante (se está creando un nuevo objeto en el sistema, pero en general no lo vamos a considerar para nuestro análisis, y tampoco tiene que ver con el hecho de que un día responda una cosa y otro día otra).

    + +

    Ejemplos como este hacen que transparencia referencial y efecto colateral no sean conceptos opuestos, ya que en este caso se debe a que la operación depende de algo externo (la fecha de la computadora).

    + +

    Ejemplo 2: método con efecto

    + +

    Dada la siguiente implementación del objeto pepita:

    + +
    object pepita {
    +  var energia = 100
    +  method vola(metros) {
    +   energia = energia - (metros + 4)
    +  }
    +}
    +
    + +

    Analicemos el mensaje: pepita.vola(20)

    + +
      +
    • Efecto colateral: SI, porque la energía de pepita antes era 100 y luego es 76.
    • +
    • Transparencia Referencial: NO, se está produciendo un efecto al disminuirse la energía de pepita. En este caso el método no retorna un valor, con lo cual no tendría sentido intentar reemplazar ese envío de mensajes por su resultado.
    • +
    • Asignación destructiva: SI, al hacer energia = … estamos cambiando a qué objeto referencia por esa variable.
    • +
    + +

    Ejemplo 3: método de consulta determinística

    + +
    object factorial {
    +  method para(numero){
    +    var resultado = 1
    +    if(numero > 0) 
    +      resultado = self.para(numero - 1) * numero
    +    return resultado
    +  }
    +}
    +
    + +

    Analicemos el mensaje: factorial.para(20)

    + +
      +
    • Transparencia Referencial: SI, el resultado sólo depende de sus argumentos, no importa en qué contexto, siempre dará el mismo resultado para el número 20.
    • +
    • Asignaciones Destructivas: SI, podemos ver que la variable local resultado primero toma el valor 1, pero luego para números mayores a 0 se modifica por el valor que corresponda.
    • +
    • Efecto colateral: NO, a pesar de que hay una asignación dentro del método, al ser sólo una variable local no se produce ningún efecto que perdure a la ejecución de ese mensaje. Esa asignación podría analizarse como efecto colateral dentro del método. Probablemente en un método tan pequeño como este no tenga importancia ese tipo de análisis, pero en el caso de algoritmos más complejos podría cobrar valor (y asumiendo que no sea posible partir un algoritmo complejo en operaciones más pequeñas que simplifiquen justamente el análisis, pero eso ya es otra cuestión).
    • +
    + +

    ¿Por qué nos interesa pensar en estos conceptos?

    + +

    Estos son algunos ejemplos concretos sobre cómo la existencia o no de efecto, asignación destructiva y transparencia referencial afectan a la hora de programar.

    + +

    Separar la lógica que hace cosas de la que consulta: Muy seguido vemos métodos (o procedimientos, dependiendo del paradigma) que tienen efecto y a su vez retornan algún valor relacionado con el mismo, estas prácticas pueden llevar a confusiones que producen un funcionamiento erróneo del sistema, sobre todo cuando el nombre del método elegido no denota que existe un efecto asociado a su ejecución. Es una buena práctica tener separada la lógica que realiza modificaciones sobre el sistema de los que sólo pretenden obtener el resultado de una consulta, que nuestros métodos tengan un único objetivo, lo cual simplifica su uso y la elección de un nombre suficientemente representativo.

    + +

    Respetar los contratos blandos: Un contrato blando es algo que cierta pieza de código requiere que cumpla el usuario para que la misma funcione de la forma esperada, pero esos requisitos no son validados de ninguna forma. Un ejemplo típico de esto está relacionado con los mensajes de colecciones que esperan recibir un bloque de código que sea sólo de consulta, o sea que no produzca ningún efecto.

    + +

    Optimizaciones: Tener asegurada la transparencia referencial permite hacer optimizaciones como las que tiene el motor de Haskell que afectan globalmente a los programas construidos con el mismo. La evaluación perezosa o lazy es posible gracias a esta característica. También lo podemos ver en Prolog que para buscar soluciones utiliza el mecanismo de Backtracking de modo que se puedan encontrar múltiples respuestas a una consulta, así como descartar los caminos por los cuales no sea posible hayar alguna, de una forma eficiente.

    + +

    Otro ejemplo viene de la mano del procesamiento en paralelo. Si tenemos un conjunto con millones de elementos y queremos filtrarlo por un criterio, ¿no puedo dividir ese conjunto en varios más pequeños, filtrarlos por separado en distintos procesadores y juntar sus resultados? Si yo aseguro que evaluar el criterio de filtrado sobre cada elemento no va a provocar ningún efecto que pueda alterar mi resultado final, esta optimización podría permitir aprovechar mucho mejor el hardware disponible. Si te interesa el tema acá hay algo para leer al respecto: Scala - Parallel Collection Framework

    + +

    Testing: El testeo unitario se basa en la premisa de que cada test sea independiente del otro y eso se logra controlando que el estado del sistema antes y después de correr cada test sea el mismo, por ese motivo es importante mantener el efecto controlado y poder revertir aquellos cambios que sobrevivan a la ejecución de cada test particular. También la transparencia referencial es importante para el testeo unitario ya que testear el resultado de una operación que depende de algo no determinístico no es viable y hace falta usar estrategias de testeo más avanzadas (Mock Objects) para evitar este tipo de dependencia.

    + +

    Preguntas frecuentes

    + +

    Leí una definición de Transparencia Referencial: “Hay transparencia referencial si al reemplazar una operación por su resultado se logra el mismo efecto”

    + +

    Con este criterio, aquí sí habría transparencia referencial:

    + +
    int a=1;
    +int c;
    +c=a++;
    +
    + +

    Ya que es lo mismo que hacer esto:

    + +
    int a=1;
    +int c;
    +c=1;
    +
    + +

    Ya que el efecto en la variable c es el mismo: va a valer 1.

    + +

    Pero para mí no es así, ya que no va a haber transparencia referencial, porque si bien se logra el mismo efecto con respecto a c, el sistema cambia (la variable a se incrementa en una unidad).

    + +

    ¿Es correcto afirmar entonces que si no hay Efecto de Lado entonces tengo garantizada la Transparencia referencial y viceversa?

    + +
    +

    En el ejemplo dado no hay transparencia referencial, es correcta la interpretación. La expresión a++ tiene el efecto colateral de modificar el valor de a, por lo tanto no puede tener transparencia referencial. Sin embargo, no es correcto que si no hay efecto entonces está garantizada la transparencia referencial (como se pone en evidencia en el ejemplo de la consulta no determinística).

    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ts-tipado.html b/wiki/articles/ts-tipado.html new file mode 100644 index 0000000000..034ab887ab --- /dev/null +++ b/wiki/articles/ts-tipado.html @@ -0,0 +1,349 @@ + + + + + + + + + + + Interfaces y union types en Typescript + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Interfaces y union types en Typescript +

    +
    + + + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Un enunciado

    + +

    Resolución con interfaces

    + +

    Resolución con union types

    + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/tutorial-de-squeak-y-pharo.html b/wiki/articles/tutorial-de-squeak-y-pharo.html new file mode 100644 index 0000000000..941846d23e --- /dev/null +++ b/wiki/articles/tutorial-de-squeak-y-pharo.html @@ -0,0 +1,564 @@ + + + + + + + + + + + Tutorial de squeak y pharo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Tutorial de squeak y pharo +

    +
    + + + +
    +

    Empezar a usar el Squeak puede ser un poco complicado porque no es muy intuitivo, les dejamos una explicación para poder arrancar con menos miedo. Pharo no es muy diferente, así que sólo aclaramos cuando difiere para no armar todo de nuevo :D

    + +

    Crear una Clase

    + +

    1) Abrir el Class Browser (System Browser): Hagan click sobre el fondo del squeak para que se les abrá el menú World -> open… y eligen Class Browser (en Pharo se llama System Browser)

    + +

    2) En la primer columna del Class Browser tienen las categorías, allí deberían crear una nueva para agrupar las clases que vayan haciendo. Para eso hacen click derecho sobre esa columna y eligen add item… (en Pharo es Add Category) Les va a pedir que ingresen el nombre para la categoría, por ejemplo, TPObjetos-grupoBle (no sé si había algún formato requerido, pero pongan algo que los identifique).

    + +

    Al darle OK les va a aparecer el template para crear clases dentro de esa categoría:

    + +

       Object subclass: #NameOfSubclass +       instanceVariableNames: '' +       classVariableNames: '' +       poolDictionaries: '' +       category: 'TPObjetos-grupoBle'

    + +

    3) Crear clases: Siempre que quieran crear una clase nueva hacen click sobre el nombre de la categoría para que les aparezca el template anterior. Lo que tienen que hacer es cambiar NameOfSubclass por el nombre real, por ejemplo, Pelicula; después para agregarle variables de instancias tienen que escribir los nombres entre las comillas simples de instanceVariableNames separadas por espacios. Si tuvieran variables de clase irían en el renglón de abajo. Recuerden que las de instancia empiezan con minúscula y las de clase con mayúscula por convención. Finalmente, si quisieran que herede de otra clase que no sea Object, cambian Object por el nombre de la superclase.

    + +

    Para dar los ejemplos vamos a usar la parte más básica de un parcial/tp “Salas de Cine”:

    + +

    Se desea hacer un sistema para una cadena de cines, en la cual guardar la información de las salas que administra la cadena y las películas que se dan en cada horario en cada una de esas salas. Para simplificar asumimos que todas las películas comienzan en punto y que duran una cantidad entera de horas. Además de su duración, de cada película se sabe su género.

    + +

       Object subclass: #Pelicula +       instanceVariableNames: 'duracion genero titulo' +       classVariableNames: '' +       poolDictionaries: '' +       category: 'TPObjetos-grupoBle'

    + +

    Una vez que completaron el template hacen click derecho -> Accept o simplemente Ctrl+S.

    + +

    Si quieren editar la definición de la clase, por ejemplo para agregar/quitar variables o cosas así, clickeando sobre el nombre de la clase debería mostrarles el código que guardaron y vuelven al paso 3.

    + +

    Para crear una subclase pueden cambiar el template para que use la superclase en vez de Object. Más detalles, acá: Cómo crear una subclase en Squeak

    + +

    Métodos

    + +

    Creando un Método

    + +

    4) Agregar métodos: Haciendo click sobre la 3er columna (donde tienen –all– y no messages) les aparece un ejemplo de cómo quedaría un método:

    + +

       message selector and argument names +       "comment stating purpose of message" +       | temporary variable names | +       statements

    + +

    Eso lo borran y escriben el método que tengan ganas. Por ejemplo:

    + +

       verificarLongitud +       "Esto de abajo es fruta, pero para que se imaginen cómo podría escribirse un método" +       ^ self genero nombre size > 10 ifTrue: [30] ifFalse: [20]

    + +

    Acá se están usando 2 mensajes aún indefinidos: genero y nombre, que son los getters de las variables de instancia. Los accessors se pueden crear directamente haciendo click derecho en el nombre de la clase y… En Squeak: -> more… -> create inst var accessors En Pharo: -> Refactor Class -> Accessors (para crear todos los que falten)

    + +

             -> Refactor instance variable -> Accessors (para elegir una variable para cual crear los accessors)

    + +

    Como todavía no había hecho eso al hacer Ctrl+S al método verificarLongitud para aceptar y que se agregue efectivamente debería aparecer un cartelito diciendo que no conoce esos selectores porque no hay ninguna clase que defina genero y nombre, entonces les tira un par de opciones por si se confundieron, siendo la primera lo que tipearon, las siguientes algunas alternativas existentes y al final Cancel para seguir editando el método sin aceptar los cambios.

    + +

    Mucho más que eso no hay para lo que es definir las clases. Lo que quedaría es armar el programita -> workspace (no main =P). Lo que tiene de copado es que tienen un ambiente vivo y pueden mandarles mensajes a los objetos como se les de la gana, no es necesario tener todo el programa armado y darle run, lo pueden ir armando a la par que le agregan los métodos a las clases. Así que…

    + +

    Modificando un Método

    + +

    Para modificar un método, si se equivocaron, pueden hacerlo seleccionando el método, haciendo los cambios y apretando aceptar. Pero ¡Ojo! ‘’’ No se puede modificar así nomás el nombre de un método. ‘’’ Si se quiere cambiar su selector (cualquier cosa del nombre ó los parámetros) deberán hacerlo así:

    + +
      +
    • Clck en la lista de métodos sobre el que quieren modificar
    • +
    • Botón derecho en el método -> refactor method
    • +
    + +

    Y ahí les ofrece varias cosas, eligen lo que quieren hacer.

    + +

    Escribir Un Workspace

    + +

    5) El Workspace: Volvemos al fondo del Squeak, hacen click para que aparezca World -> open… -> workspace

    + +

    Ahí les aparece un cuadro de texto en blanco para que tiren código. Lo primero que podemos hacer es instanciar una Pelicula y settearle un par de atributos. Así que escribimos lo siguiente en el workspace:

    + +

       saw := Pelicula new. +   saw titulo: 'El Juego del Miedo'. +   saw duracion: 2.

    + +

    Si seleccionan esas tres líneas (para seleccionar todo tienen Ctrl+espacio) y hacen Ctrl+d (do it) se evalua ese código. Para ver si anduvo todo bien pueden escribir lo siguiente en el workspace:

    + +

       saw titulo.

    + +

    Si se paran al final de ese renglón (para evaluar una sola línea no es necesario seleccionar, si seleccionan todo se va a evaluar todo desde el principio nuevamente y eso no tiene gracia, jeje) y le dan Ctrl+p (print it) les va a aparecer al final de la línea y seleccionado para su conveniente borrado el string ‘El Juego del Miedo’

    + +

    Otra forma de ver qué onda con nuestros objetitos es pararse sobre la variable con la que lo referenciamos, en este caso saw, y hacer ctrl+i (inspect it). Eso les abre una ventanita donde pueden ver a qué está referenciando cada una de las variables. En este caso tendrían lo siguiente:

    + +

       self -> a Pelicula +   all inst vars: +   duracion: 2 +   titulo: 'El Juego del Miedo' +   genero: nil

    + +

    Claro, el genero está en nil porque no le setteamos nada, de hecho ni siquiera creamos la clase Genero. Hagamos eso así probamos verificarLongitud…

    + +

    Creamos la clase Genero dentro de la categoría TPObjetos-GrupoBle con las v.i. que quieran, incluyendo nombre. Después create inst var accessors y listo.

    + +

    Volvemos al workspace… agregamos el siguiente código:

    + +

       terror:=Genero new. +   terror nombre: 'Terror'. +   saw genero: terror. +    +   saw verificarLongitud.

    + +

    Seleccionamos ese código y le damos ctrl+p y al final de ese código seleccionado aparece el número 20 que es lo que esperábamos.

    + +

    Métodos de Clase

    + +

    5) Métodos de clase: supongamos que el género lo quieren instanciar directamente como:

    + +

       terror := Genero conNombre: 'Terror' yDuracionMaxima: 1.5.

    + +

    Ahí habría que escribir el método de clase conNombre: yDuracionMaxima: Para eso vamos a la clase Genero en el Class Browser y hacemos click en el botoncito que dice class (hasta ahora veníamos trabajando del lado de las instancias). De manera análoga, hacemos click en la tercer columna para que nos aparezca el ejemplo de método y escribimos lo siguiente:

    + +

       conNombre: unNombre yDuracionMaxima: unaDuracion +   ^ self new +           nombre: unNombre; +           duracionMaxima: unaDuracion.

    + +

    Ahí lo único loco que hice fue usar un truquito que no contamos en clase me parece que es el de enviar mensajes en cascada. La forma de evaluación de ese código sería: primero self new por ser unario, eso me da una instancia de Genero, a esa instancia se le envía el mensaje nombre: con el parámetro que nos llegó de afuera unNombre. El punto y coma indica que la siguiente sentencia es un mensaje que se le envía al mismo objeto de antes, o sea al genero que instanciamos recién. Le mandamos duracionMaxima: y le setteamos la duración correspondiente.

    + +

    Finalmente retorna al objeto ya inicializado (el ^ es lo que tiene menor precedencia) y lo que va a retornar es lo que haya retornado el último envío de mensajes. Como duracionMaxima: es un setter por defecto que no tiene ningún ^ estamos seguros de que lo que va a retornar (porque TODOS los mensajes retornan un objeto) es al objeto receptor.

    + +

    A modo informativo, si duracionMaxima: retornara algo diferente de self habría que hacer lo siguiente:

    + +

       conNombre: unNombre yDuracionMaxima: unaDuracion +       ^ self new +               nombre: unNombre; +               duracionMaxima: unaDuracion; +               yourself.

    + +

    Para que nos retorne al objetito receptor.

    + +

    La otra alternativa que a mí me resulta medio incómoda pero es la más fácil es definirle un mensaje de instancia al género que sea nombre: yDuracionMaxima: que le settee internamete las dos variables al objeto. Con lo cual quedaría lo siguiente:

    + +

       conNombre: unNombre yDuracionMaxima: unaDuracion +   ^ self new nombre: unNombre yDuracionMaxima: unaDuracion.

    + +

    Y del lado de las instancias (hacemos click en instance) agregamos el método nombre: yDuracionMaxima: que haga lo siguiente:

    + +

       self nombre: unNombre. +   self duracionMaxima: unaDuracion

    + +

    Y no retornamos nada porque queremos que nos retorne self.

    + +

    Ahora podemos refactorizar nuestro workspace y nos quedaría algo así:

    + +

       saw := Pelicula new. +   saw titulo: 'El Juego del Miedo'. +   saw duracion: 2. +    +   terror:=Genero conNombre: 'Terror' yDuracionMaxima: 1.5. +   saw genero: terror. +    +   saw verificarLongitud.

    + +

    Hacemos Ctrl+space + Ctrl+p y mágicamente sigue dando 20 =D O sea que hicimos las cosas bien y no rompimos nada.

    + +

    Guardando nuestro trabajo

    + +

    Grabar la Imagen

    + +

    6) Guardar los cambios: Hagan click en el fondo para abrir World -> save

    + +

    Grabar en un archivo .st

    + +

    7) FileOut: Para hacer la entrega tienen que hacer un fileOut de la categoría. Para eso sólo le dan click derecho al nombre de la categoría -> fileOut. Cuando yo lo hice no me preguntó en dónde guardar ni con qué nombre, simplemente se guardó en mi directorio de instalación del Squeak con el nombre de la categoría y extensión .st

    + +

    No se preocupen si ven muchos !!!! en el archivo, es lo que tienen que pasar. Después de todo no fue hecho para ser leído por mortales, nada más para ser importado en otro Squeak o para los paspados que prefieren la entrega en papel, jajajaj (mentira, es útil tenerlo en papel, y con un poquito de cancha es hasta fácil de seguir)

    + +

    Grabar el Workspace

    + +

    8) Guardar el Workspace: obviamente el fileOut sólo les guarda el código de las clases que estén en la categoría, el ws hay que guardarlo aparte. Pueden hacer simplemente copy/paste y pegarlo a un txt normal o pueden usar la opción de guardado que trae el Squeak. Para eso: click derecho sobre el workspace -> more… -> save contents to file

    + +

    Le ponen el nombre que quieran y la extensión la pueden dejar como txt o cambiarla a st, que es como se guarda en la otra versión de Smalltalk. Se los va a guardar en la misma carpeta por default en la que se hizo el fileOut.

    + +

    Importar un archivo .st

    + +
      +
    • Arrastrar el archivo .st y soltarlo sobre la imagen de Pharo. Le dan FileIn Entire File y ¡Listo!
    • +
    + + + +
      +
    • Otra forma:
    • +
    + +

    1) Botón derecho sobre el fondo. En el menú World van a Tools -> File Browser.

    + +

    2) En el File Browser van a ver tres paneles:el de la izquierda muestra el arbol de directorios y carpetas de su sistema.

    + +

    3) Seleccionar la carpeta donde esta instalado Pharo, que es donde va a estar el archivo .st que quieren importar. En el panel de la derecha, van a ver la lista de los archivos incluidos en esa carpeta.

    + +

    4) Seleccionen el archivo .st. En el panel inferior van a ver el codigo que escribieron, y arriba de los paneles superiores van a aparecer varios botones, elijan Install

    + +

    Shortcuts / Atajos del Teclado / Fatalities

    + +
      +
    • Ctrl+b seleccionando una clase* para que se abra un Class Browser sobre esa clase.
    • +
    • Ctrl+n seleccionando un selector* para ver sus Senders (se abre una lista de métodos desde donde se envía ese mensaje, también vale para cuando se usa un symbol igual al mensaje, onda #size).
    • +
    • Ctrl+m seleccionando un selector* para ver sus Implementors (se abre una lista de métodos para ese mensaje)
    • +
    • Ctrl+shift+n sobre una clase* para ver en dónde se usa (References)
    • +
    • Ctrl+i sobre un objeto nos permite inspeccionarlo por adentro
    • +
    • Alt+punto para mandar una interrupción (útil para cuando uno se la manda y queda ejecutando algo recursivamente, se interrumpe la ejecución y se puede debuggear el stacktrace desde donde interrumpimos)
    • +
    + +

    * En cualquiera de estos casos, “seleccionar” se puede entender como seleccionar un selector / nombre de clase dentro de un cacho de código (workspace, definición de un método en el class browser, el debugger, etc), o bien seleccionarlo en un listado de cualquier browser (el Class Browser, la lista de variables de instancia y temporales que aparece en un debugger, una lista de senders que hayas abierto, etc).

    + +

    Por cierto, todas las cosas que se listan con Ctrl también funcionan con Alt en Windows (a veces sólo funcionan con Alt).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/tutorial-de-squeak.html b/wiki/articles/tutorial-de-squeak.html new file mode 100644 index 0000000000..e0057850ef --- /dev/null +++ b/wiki/articles/tutorial-de-squeak.html @@ -0,0 +1,302 @@ + + + + + + + + + + + Tutorial de squeak + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Tutorial de squeak +

    +
    + + + +
    +
      +
    1. REDIRECT Tutorial de Squeak y Pharo
    2. +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/tutoriales-para-desarrollo-java.html b/wiki/articles/tutoriales-para-desarrollo-java.html new file mode 100644 index 0000000000..9777dae673 --- /dev/null +++ b/wiki/articles/tutoriales-para-desarrollo-java.html @@ -0,0 +1,329 @@ + + + + + + + + + + + Tutoriales para desarrollo java + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/typeclasses.html b/wiki/articles/typeclasses.html new file mode 100644 index 0000000000..fddac36e23 --- /dev/null +++ b/wiki/articles/typeclasses.html @@ -0,0 +1,554 @@ + + + + + + + + + + + Typeclasses + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Typeclasses +

    +
    + + + +
    +

    Introducción

    + +

    Problema

    + +

    Si tenemos la multiplicacion (*) definida para tanto Int como Float, luego

    + +

    + square x = x*x +

    + +

    debería transformarse en tiempo de compilación en dos funciones distintas

    + +

    square (para ints) square (para floats)

    + +

    Lo cual crece exponencialmente, por ejemplo con funciones como

    + +

    + squares (x,y,z) = (x*x, y*y, z*z) +

    + +

    que sería traducida en 8 funciones distintas, de modo que se pueda usar tanto con una tupla de tipo (Int, Float, Int) como (Float, Float, Float) o (Int, Int, Float)…

    + +

    Typeclasses al rescate

    + +

    Las typeclasses son un contrato o tipo de datos abstracto que agrupa las funciones sobrecargadas: es decir, definen una lista de funciones que un tipo deber implementar para considerarse de esa clase. Ejemplo: la typeclass Num dice que todos aquellos tipos que sean Num (Int o Float por ejemplo) van a definir las funciones (+) y (*) y de que tipos son.

    + +

    Las typeclasses tienen como primer consecuencia que funciones como squares, que tenía 8 tipos posibles, tenga uno solo:

    + +

    + squares :: Num a, Num b, Num c => (a,b,c) -> (a,b,c) +

    + +

    Donde Num es un typeclass que indica que a es un tipo concreto (como Int o Float) que cumple con ese contrato, y lo mismo para b y c.

    + +

    Es importante que quede claro que una typeclass no es un tipo concreto, sino una restricción sobre una variable de tipo (que puede tomar como valores posibles por ejemplo Int o Float, que sí son tipos concretos).

    + +

    Las typeclasses de Haskell más usadas

    + +

    Num, Ord y Eq

    + +

    Nos gustaría poder definir los siguientes tipos (a.k.a dominios e imágenes)

    + +

    (+) :: (Si asumimos que a es numérico) entonces a -> a -> a

    + +

    (>) :: (Si asumimos que a es ordenable) entonces a -> a -> Bool

    + +

    (==) :: (Si asumimos que a es equiparable) entonces a -> a -> Bool

    + +

    En Haskell eso se escribe de la siguiente manera

    + +
    +  (+) :: (Num a) => a - > a -> a
    +(>) :: (Ord a) => a - > a -> Bool
    +(==) :: (Eq a) => a - > a -> Bool
    +
    +
    + +

    Num, Ord y Eq son restricciones de tipo, en Haskell se las conoce como Typeclasses (no confundan esto con el término Clase que usamos en el paradigma de objetos!!)

    + +

    En cada Typeclass se definen un conjunto de funciones que los tipos pertenecientes deben implementar. A continuación mostramos algunos ejemplo de funciones que se definen en Num, Ord y Eq.

    + +
    +  Num a:
    +(+), (-), (*) :: a -> a -> a
    +negate, abs, signum :: a -> a
    +etc.
    +
    +Ord a:
    +(<), (<=), (>=), (>) :: a -> a -> Bool
    +max, min :: a -> a -> a
    +etc.
    +
    +Eq a:
    +(==) :: a -> a -> Bool
    +(/=) :: a -> a -> Bool
    +
    +
    + +

    Veamos cómo impacta esto en la definición de algunas funciones de listas por ejemplo:

    + +
    +  elem :: (Eq a) => a -> [ a ] -> Bool
    +elem unElemento unaLista = any (unElemento==) unaLista
    +
    +maximum :: (Ord a) => [a] -> a
    +maximum lista = foldl1 max lista
    +
    +
    + +

    Lo que nos interesa más que nada es que se note que gracias a que existen las typeclasses que explicitan cuál es el conjunto mínimo de funciones que el tipo concreto debe definir para formar parte de ella, luego podemos construir otras cosas encima usando esas funciones y vamos a poder sacarle el mismo provecho. Las funciones elem y maximum van a funcionar tanto para [Int] como para [Char] (o sea, para strings).

    + +

    ¿Qué tipos pertenecen a cada restricción?

    + +

    Num: Los tipos concretos más comunes que integran esta familia son Int y Float.

    + +

    Ord: Además de incluír a la mayoría de los tipos numéricos (como Int y Float) incluye a los caracteres, los booleanos (sí, hay un orden preestablecido para los booleanos aunque no sea común usarlo). También incluye a las listas y las tuplas siempre y cuando los tipos que las compongan sean ordenables (por ejemplo los Strings, que son listas de caracteres, son ordenables). Las funciones no son ordenables.

    + +

    Eq: Todos los Ord y los Num son también esquiparables. Para las listas y tuplas, son equiparables si los tipos que las componen lo son. Las funciones no son equiparables.

    + +

    ¿Y los data? Algo muy común es que querramos que nuestros tipos de datos sean equiparables. Si los tipos de datos que componen a nuestros data lo son, alcanza con derivar Eq y no necesitaremos definir la igualdad. De lo contrario, para que sea Eq será necesario dar un pasito más avanzado y declarar que nuestro tipo de dato es instancia de la typeclass Eq e incluir una definición para la función (==) como se explica en el artículo sobre data.

    + +

    También es muy común querer que nuestros datos se puedan mostrar, y para eso existe otra typeclass que es

    + +

    La restricción Show

    + +

    Cuando utilizamos el intérprete, los resultados de nuestras funciones son valores (valores simples, compuestos o funciones), para que se puedan mostrar por pantalla esos valores tienen que tener una representación en forma de cadena de caracteres (String).

    + +

    La magia la realiza una función llamada show

    + +
    +  > show 3
    +"3"
    +> show True
    +"True"
    +> show (2,3)
    +"(2,3)"
    +
    +
    + +

    Ahora bien, no todos los valores pueden ser parámetro de la función show. Por ejemplo las funciones no tienen una representación en String

    + +
    +  > show length
    +Error
    +
    +
    + +

    Debido a esto, cuando quieren mostrar por pantalla una lista de funciones (ej [fst,snd]), una función parcialmente aplicada como (3+), o en general una función que retorna una función les va a tirar un error.

    + +

    Veamos el tipo de la función show

    + +
    +  show :: (Show a) => a -> String
    +
    +
    + +

    La única función que se define en la restricción Show es la función show

    + +

    Qué tipos pertenecen a la restricción Show? Bool, Char, Double, Float, Int, Integer, (Show a) => [ a ] –Listas, (Show a,b) => (a,b) –Tuplas

    + +

    Resumiendo: casi todos todos los tipos menos el tipo función

    + +

    Al igual que se mencionó anteriormente para Eq, podemos hacer que un tipo de dato propio pueda ser mostrado con la función Show ya sea usando deriving si sólo se compone de otros datos de tipo Show o haciendo que sea instancia de Show y definiendo la función Show como querramos.

    + +

    Para cerrar: El truco detrás de la magia

    + +

    Las typeclasses se pueden traducir/reescribir a un lenguaje sin typeclasses. Y por lo tanto, como pueden reutilizarse los mecanismos de inferencia de tipos de uno para el otro.

    + +

    Para esta traducción, se usará la metáfora de un method dictionary. Cada tipo va a tener un diccionario con sus funciones sobrecargadas. Luego, cada función con polimorfismo paramétrico, recibe como parámetro el method dictionary y usa la función adecuada:

    + +

    Ejemplo:

    + +

    + square x = x * x +

    + +

    se transforma en algo como

    + +
    +  --ambos diccionarios son del mismo tipo (que es el tipo definido en la typeclass ;) )
    +dictInt = ...
    +dictFloat = ....
    +
    +multi dict = dict !! 1 -- suponiendo que la función multiplicación esta en el diccionario en la posición 1
    +square dict x = multi dict x x
    +
    +
    + +

    Y cuando ejecutamos

    + +

    + square 3 +

    + +

    se traduce, como 3 es un Int, en algo como

    + +

    + square dictInt 3  +

    + +

    Alguien que ya tiene conocimientos sobre el paradigma orientado a objetos podría encontrar similitudes con el polimorfismo de ese paradigma desde el punto de vista del uso, pero la realidad es que hay magia en el medio a nivel compilador de modo que siempre se sabe qué definición de función se usará en tiempo de compilación (no se hace un dispatch dinámico).

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/typedefs-y-tipos-anonimos.html b/wiki/articles/typedefs-y-tipos-anonimos.html new file mode 100644 index 0000000000..b185369b8b --- /dev/null +++ b/wiki/articles/typedefs-y-tipos-anonimos.html @@ -0,0 +1,372 @@ + + + + + + + + + + + Typedefs y tipos anonimos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Typedefs y tipos anonimos +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Descripción

    + +

    typedef es una construcción del lenguaje C que nos permite darle alias a tipos existentes (sinónimos de tipos), de forma similar al type de Haskell.

    + +

    Esto es particularmente útil a la hora de trabajar en ANSI C con estructuras. Por ejemplo, si definimos una estructura TanqueDeAgua de la siguiente forma:

    + +
    +  struct TanqueDeAgua {
    +  int capacidad_maxima;
    +  int temperatura_del_agua;
    +  //etc
    +} 
    +
    +
    + +

    cada vez que querramos utilizar este tipo deberemos escribir:

    + +
    +  struct TanqueDeAgua un_tanque;
    +
    +
    + +

    Lo cual es ciertamente verborrágico, y nos acopla mucho más a la implementación: cuando hablo de un tanque de agua, no me interesa si es un struct, un union u otra cosa.

    + +

    La solución a este problema es usar un sinónimo de tipo:

    + +
    +  typedef struct _TanqueDeAgua {
    +  int capacidad_maxima;
    +  int temperatura_del_agua;
    +  //etc
    +} TanqueDeAgua
    +
    +
    + +

    Es decir, TanqueDeAgua es ahora un sinónimo para struct TanqueDeAgua, con lo que puedo escribir

    + +

    TanqueDeAgua un_tanque.

    + +

    De hecho, dado que siempre referiremos a este tipo a través de su sinónimo, no es necesario darle un nombre a la estructura _TanqueDeAgua, ya que podemos definir una estructura anónima:

    + +
    +  typedef struct {
    +  int capacidad_maxima;
    +  int temperatura_del_agua;
    +  //etc
    +} TanqueDeAgua
    +
    +
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-arquitectura-general.html b/wiki/articles/ui-arquitectura-general.html new file mode 100644 index 0000000000..b1a1927364 --- /dev/null +++ b/wiki/articles/ui-arquitectura-general.html @@ -0,0 +1,377 @@ + + + + + + + + + + + Integracion de la ui en una arquitectura de un sistema de software + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Integracion de la ui en una arquitectura de un sistema de software +

    +
    + + + + + +
    +

    Arquitectura usual de una aplicación de software

    + +

    Para generar una aplicación, podemos dividir lógicamente los componentes según el rol que juegan dentro del sistema en sí mismo:

    + +
      +
    • +

      Presentación: son elementos que trabajan con la interfaz de usuario, dependientes de la tecnología

      +
    • +
    • +

      Dominio: son las abstracciones que tienen significado para el que conoce el negocio (una factura, un alumno, un proveedor, una encuesta de satisfacción de servicio, etc.)

      +
    • +
    • +

      Persistencia: son elementos que trabajan en almacenar y recuperar la información del sistema en un medio que persista en el tiempo (que no sea volátil).

      +
    • +
    + +

    Formas de división de responsabilidades entre cada una de esas partes

    + +

    Esta división de responsabilidades se suele denotar como capas de una aplicación. Aquí preferimos utilizar el término concern o al menos aclarar que la división no implica separación física de los componentes. La clasificación en presentación, dominio y persistencia tiene que ver con el objetivo que cumple cada componente dentro de la aplicación.

    + +

    Interacción entre la UI y el dominio del sistema

    + +

    Una idea bastante instalada en el mercado es abstraer la presentación del dominio tanto como sea posible. De hecho algunos piensan que lo mejor es que no se conozcan/ni se hablen.

    + +

    Entonces la presentación habla con un objeto intermedio que no tiene comportamiento, solo alguno de los atributos a los que se accede mediante getters y setters. Como la característica de estos objetos es transferir informacion del dominio a la vista se los denomina Data Transfer Objects o DTO.

    + +

    Un ejemplo podría ser: en la actualización de un empleado se ingresan nombre, apellido, DNI, fecha de ingreso y cargo. En lugar de que la vista conozca a un objeto Empleado que tenga métodos de negocio (por ejemplo que calcule la antigüedad, que sepa cuánto cobra, que conteste cuántas horas trabajó un mes, etc.) generamos un EmpleadoDTO, que tiene solamente nombre, apellido, DNI, sueldo mensual en base al cargo y antigüedad, éstos últimos dos atributos calculados. El EmpleadoDTO no sabe calcular su antigüedad, ni tiene relación con otros objetos. Esta técnica puede ser útil cuando estamos trabajando en ambientes distribuidos, es decir, en muchas VM que necesito sincronizar.

    + +

    Pero al separar la presentación y el negocio de esta manera poco feliz estoy metiendo una solución que para comunicar dos ambientes OO descarta las principales ideas del paradigma (el objeto como un ente que agrupa atributos y comportamiento). Incluso es un problema porque tenemos varios objetos que están representando a un empleado:

    + +
      +
    • el Empleado
    • +
    • el EmpleadoDTO
    • +
    + +

    En definitiva pareciera que la vista no se mezcla con el negocio pero el acoplamiento es claro: para saber cuándo fue la última vez que le pagué el sueldo necesito:

    + +
      +
    1. generar un nuevo método de negocio si no lo tengo, pero también
    2. +
    3. agregar un atributo al EmpleadoConsultaDTO para que la vista lo pueda mostrar
    4. +
    + +

    Nuestra idea es que la presentación no solo hable con el dominio sino que le pida todo lo que le tenga que pedir: en el ejemplo anterior sería muy bueno que la vista le pregunte directamente al empleado cuál fue la última vez que le pagué.

    + +

    Links relacionados

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-clasificacion.html b/wiki/articles/ui-clasificacion.html new file mode 100644 index 0000000000..2005da273b --- /dev/null +++ b/wiki/articles/ui-clasificacion.html @@ -0,0 +1,497 @@ + + + + + + + + + + + Clasificacion de las UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Clasificacion de las UI +

    +
    + + + + + +
    +

    Concepto de cliente y servidor

    + +

    Una aplicación puede pensarse desde la óptica del

    + +
      +
    • cliente: el que realiza pedidos
    • +
    • servidor: el que responde a esos pedidos
    • +
    + +

    La separación puede ser:

    + +
      +
    • lógica: ambos componentes residen en la misma máquina
    • +
    • lógica y física: además de pensarse como componentes separados el usuario utiliza un cliente en su máquina y accede al servidor que concentra esos pedidos y se encarga de responderlos.
    • +
    + +

    ¿Qué tipo de pedidos hace el cliente? Esto depende de la arquitectura sobre la cual trabajemos:

    + + + +

    Arquitectura de las UI

    + +
      +
    1. Aplicación centralizada
    2. +
    3. Aplicación distribuida (Cliente/Servidor)
    4. +
    + +

    Aplicación centralizada

    + +

    + centralizada +

    + +

    El cliente tiene poca o nula inteligencia. El servidor tiene muchas responsabilidades, esto es:

    + +
      +
    • recibe los parámetros del cliente, los valida y los transforma
    • +
    • procesa las acciones de negocio
    • +
    • transforma los resultados de esas acciones y
    • +
    • genera la visualización que va a obtener el cliente como respuesta.
    • +
    + +

    Del lado del cliente casi no hay lógica, ni de presentación ni de negocio, es una “terminal boba”. Es el modelo que siguen las arquitecturas mainframe y la web en sus orígenes, donde el browser solo tenía capacidades de mostrar la información y los controles que el servidor le enviaba.

    + + + +

    Cliente / Servidor - Aplicaciones distribuidas

    + +

    + centralizada +

    + +

    En este tipo de aplicaciones, se asume que

    + +
      +
    • los clientes tienen más capacidad de procesamiento, por lo tanto suelen presentar una interfaz de usuario más “rica” que las aplicaciones centralizadas (por eso también se las suele llamar RIA o Rich Internet Applications)
    • +
    • la comunicación hacia el servidor suele ser un cuello de botella, así que se trata de minimizar la cantidad de información a pasar entre cliente y servidor. Por lo general el cliente hace un pedido, la consulta se procesa en el servidor y vuelve la información procesada para que el cliente la presente en un formato amigable.
    • +
    • las aplicaciones distribuidas son más complejas arquitecturalmente: se dividen en 2, 3 hasta n niveles
    • +
    + +

    Peer to Peer

    + +

    Otra alternativa consiste en la red peer-to-peer (P2P), donde cada equipo actúa como cliente o servidor dependiendo de si hace un pedido o lo responde (consumer/producer). No existe el servidor como equipo de sincronización, sino que cada equipo mantiene su propio estado:

    + +

    + peer-to-peer +

    + +

    Ejemplos de aplicaciones peer to peer son Skype, eMule, μTorrent, entre otras.

    + +

    Análisis comparativo P2P vs. C/S

    + +

    Ventajas de la visión Cliente/Servidor

    + +
      +
    • Centralización del control: los accesos, recursos y la integridad de los datos son controlados por el servidor de forma que un programa cliente defectuoso o no autorizado no pueda dañar el sistema. Esta centralización también facilita la tarea de poner al día datos u otros recursos (mejor que en las redes P2P).
    • +
    • Escalabilidad: se puede aumentar la capacidad de clientes y servidores por separado. Cualquier elemento puede ser aumentado (o mejorado) en cualquier momento, o se pueden añadir nuevos nodos a la red (clientes y/o servidores).
    • +
    • Dado que hay una cierta independencia entre clientes y servidores, es posible reemplazar, reparar, actualizar o trasladar alguno de ellos con un bajo impacto, siempre y cuando ciertas variables se mantengan estables (debe estar un servidor activo, hay que asegurar el enlace entre los nodos, etc.)
    • +
    • Hay muchas más tecnologías desarrolladas para el paradigma de C/S.
    • +
    + + + +

    Ventajas de la visión Peer to Peer

    + +
      +
    • La congestión del tráfico ha sido siempre un problema en el paradigma de C/S. Cuando una gran cantidad de clientes envían peticiones simultaneas al mismo servidor, puede ser que cause muchos problemas para éste (a mayor número de clientes, más problemas para el servidor). Al contrario, en las redes P2P como cada nodo en la red hace también de servidor, cuanto más nodos hay, mejor es el ancho de banda que se tiene.
    • +
    • El paradigma de C/S clásico no tiene la robustez de una red P2P. Cuando un servidor está caído, las peticiones de los clientes no pueden ser satisfechas. En la mayor parte de redes P2P, los recursos están generalmente distribuidos en varios nodos de la red. Aunque algunos salgan o abandonen la descarga; otros pueden todavía acabar de descargar consiguiendo datos del resto de los nodos en la red.
    • +
    • El software y el hardware de un servidor son generalmente muy determinantes: se necesita un buen “fierro” para que un servidor de soporte a una gran cantidad de clientes.
    • +
    • El cliente no dispone de los recursos que puedan existir en el servidor y viceversa. Por ejemplo, una aplicación que ejecuta en el servidor no puede escribir en el disco local del cliente.
    • +
    + + + +

    Interfaces orientadas a caracter y gráficas

    + +
      +
    • Orientadas a caracter: las consolas de configuración de routers, o las consolas de administración de herramientas como git, Maven o Travis, el intérprete de comandos de los sistemas operativos, el sistema de reserva de vuelos que trabaja con comandos específicos vs.
    • +
    • las interfaces gráficas: las que vamos a trabajar mayoritariamente a lo largo de la materia.
    • +
    + +

    ¿Qué características tienen las interfaces orientadas a caracter?

    + +
      +
    • son menos intuitivas, requiere memorizar comandos y códigos internos
    • +
    • por esto se tarda más en aprender las operaciones que con las interfaces gráficas
    • +
    • una vez pasada la curva de aprendizaje los usuarios expertos trabajan mucho más velozmente que en la modalidad gráfica
    • +
    + + + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-definiciones-iniciales.html b/wiki/articles/ui-definiciones-iniciales.html new file mode 100644 index 0000000000..90c8bf591c --- /dev/null +++ b/wiki/articles/ui-definiciones-iniciales.html @@ -0,0 +1,512 @@ + + + + + + + + + + + Definiciones iniciales de ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Definiciones iniciales de ui +

    +
    + + + + + +
    +

    Interfaz de usuario

    + +

    Es todo lo que permite a un usuario interactuar con el sistema. Una interfaz se implementa por lo general con una pantalla, pero no es el único dispositivo posible.

    + +

    Es todo lo que permite a un usuario interactuar con el sistema: esto incluye componentes lógicos (software) y físicos (hardware). Interfaz de Usuario también se puede abreviar por sus siglas en inglés: UI (User Interface) y en general se suele hablar de la interfaz gráfica como la parte de presentación de una aplicación.

    + +

    Objetivo de una materia que enseña UI

    + +

    Naturalmente, el objetivo de la materia es aprender a programar y diseñar interfaces de usuario. Sin embargo, la construcción de interfaces de usuario presenta muchos aspectos distintos y por eso conviene entender en cuáles vamos a hacer foco.

    + +

    Diseño gráfico y diseño de sistemas

    + +

    En primer lugar, cuando decimos “diseño”, nos referimos tanto al diseño de software como al diseño gráfico:

    + +
      +
    • el diseño de sistemas se preocupa por distribuir correctamente las responsabilidades de los componentes que forman una aplicación, para lo cual necesitamos aplicar los conceptos y patrones de diseño que previamente incorporamos
    • +
    • el diseño gráfico de una aplicación trabaja la disposición del contenido, la elección de colores (principal, secundario, de fondo, etc.), la iconografía, logos, imágenes, la usabilidad de manera que sea cómoda e intuitiva para el usuario y ofrezca un mínimo de resistencia o de adaptación.
    • +
    + +

    Si bien una materia del ámbito de las TIC está más relacionada con el primer punto, no es menor la preponderancia que adquiere últimamente el diseño gráfico, ya sea porque es una responsabilidad directamente delegada a quien construye la UI o bien constituye una actividad interdisciplinaria con un especialista.

    + +

    Nuestro objetivo también es concentrarnos en producir aplicaciones que se destaquen por sus cualidades de mantenibilidad, flexibilidad, claridad, robustez, entre otras. En el ámbito específico de las interfaces de usuario, un criterio importante será separar la responsabilidad correspondiente a la interfaz de usuario de la lógica de dominio. Repasemos entonces de qué hablamos cuando hablamos de “dominio” o “negocio”.

    + +

    Modelo de dominio

    + +

    Cuando le pedimos al sistema que haga algo, hay reglas que rigen el negocio que manejamos.

    + +

    Si el cliente sólo puede pagar con cheque a 30/60/90 días, hay una regla de negocio que lo dice. Si un alumno no puede anotarse en un final porque debe una correlativa, hay otra regla de negocio que lo dice. Si un empleado cobra un 10% del sueldo básico por presentismo, hay otra regla de negocio que lo dice.

    + +

    Lo que forma parte del dominio de mi aplicación es encontrar

    + +
      +
    • un cliente que tenga un método
    • +
    + +
    +
    +
    +      public void pagar(TipoPago tipoPago, BigDecimal monto)
    +
    +    
    +
    +
    + +

    donde se resuelva esa responsabilidad

    + +
      +
    • un alumno que tenga un método
    • +
    + +
    +
    +
    +      public void inscribirseAFinal(Materia materia)
    +
    +    
    +
    +
    + +

    donde se resuelva esa responsabilidad

    + +
      +
    • etc.
    • +
    + +

    O sea,

    + +
      +
    • si programamos con objetos, el modelo de dominio se compone de objetos con responsabilidades y relaciones que permiten definir los casos de uso del negocio.
    • +
    • si programamos en otro paradigma, el modelo de dominio serán las entidades + los procesos que resuelven las cosas que necesito para la aplicación.
    • +
    + +

    Complejidades del dominio y de la UI

    + +

    Pongamos por caso esta interfaz conocida de Twitter:

    + +

    + twitter +

    + +

    El caso de uso “Twittear” parecería no tener una UI tan compleja, aun así, la página chequea todo el tiempo la cantidad de caracteres que escribo y en una forma gráfica está mostrando el estado de mi tweet, e incluso debe deshabilitar el botón de “Enviar tweet” si excedo el máximo permitido.

    + +

    Por otra parte, una vez validado, el mensaje que recibe el negocio es algo como:

    + +
    +
    +
    +      twitter.agregarTweet(nuevoTweet)
    +
    +    
    +
    +
    + +

    que debería incorporar ese nuevo tweet a la colección (la persistencia requiere de un objeto arquitectural que normalmente está fuera del alcance del objeto de dominio).

    + +

    En general, la lógica de la presentación suele ser siempre mucho más compleja que la del negocio, aun cuando el negocio pueda (y debería) ayudar a la UI a agregar funcionalidades que mejoren la experiencia de usuario.

    + +
    +

    Corolario: no es verdad que si el dominio está bien construido la presentación se hace sola, y la implementación de la presentación debería estar a cargo de la gente con más experiencia, algo que lamentablemente no siempre sucede

    +
    + +

    ¿Qué objetivos nos proponemos al programar una interfaz de usuario?

    + +

    Por supuesto que ande, pero además vamos a priorizar ciertas cualidades de diseño: mantenibilidad, flexibilidad, claridad, robustez, entre otras. En particular tratar de no mezclar ideas de presentación con negocio. O sea, separar la lógica para definir la interacción con el usuario y la lógica propia del dominio. ¿Por qué?

    + +
      +
    • porque no quiero que mi dominio se vea afectado por cuestiones tecnológicas.
    • +
    • porque eso me lleva a perder cohesión en los objetos de presentación, que además de encargarse de mostrar la información tienen que atacar cuestiones de negocio. Entonces en dos pantallas distintas tengo que repetir la misma validación o el mismo comportamiento.
    • +
    • porque tengo más restricciones a nivel usuario y tecnológicos del lado de la UI (es la parte más compleja y la menos madura, cuesta encontrar buenas abstracciones)
    • +
    + + + +

    Volviendo al ejemplo de Twitter,

    + +
      +
    • saber qué color de fondo mostrar en el texto ==> es responsabilidad de la UI
    • +
    • determinar qué texto está excedido del tamaño de un tweet ==> es responsabilidad del dominio
    • +
    • saber la longitud de un tweet ==> es responsabilidad del dominio
    • +
    • saber si un tweet está excedido ==> es responsabilidad del dominio
    • +
    • saber si un tweet está cercano a excederse ==> es responsabilidad del dominio
    • +
    • mostrar un color celeste, amarillo o rojo como indicador de que el tweet tiene el tamaño apropiado, está cercano a excederse o definitivamente se excedió ==> es responsabilidad de la UI
    • +
    + +

    Mantener separados estos concerns facilita el cambio de tecnologías de la UI, el testeo unitario de ese dominio, entre otras cosas.

    + +

    Conceptos básicos del diseño

    + + + +

    ¿Dónde interviene el acoplamiento al programar la UI? El componente de UI va a tener que conocer al componente que maneja la lógica de dominio, de otra manera la aplicación no va a funcionar. Pero tampoco es bueno que la interfaz defina lógica que es propia del cliente, o de la factura, o de un empleado o de un alumno (para más información ver Interacción entre la UI y el dominio del sistema). Es cierto que agregar un atributo que el usuario deba visualizar o modificar a través de la interfaz fuerza inevitablemente a un cambio en la UI, pero cambios en la lógica de negocio no deberían necesariamente afectar la UI. Así que otro de nuestros objetivos será minimizar el acoplamiento, no por ser puristas, sino porque nos traerá como beneficio no vernos impactados por cualquier tipo de cambio.

    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-elementos-a-tener-en-cuenta-al-programar-ui.html b/wiki/articles/ui-elementos-a-tener-en-cuenta-al-programar-ui.html new file mode 100644 index 0000000000..7ab80e2a6b --- /dev/null +++ b/wiki/articles/ui-elementos-a-tener-en-cuenta-al-programar-ui.html @@ -0,0 +1,395 @@ + + + + + + + + + + + Elementos a tener en cuenta al programar ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Elementos a tener en cuenta al programar ui +

    +
    + + + + + +
    +

    Objetivo

    + +

    Al trabajar con interfaces de usuario, aparecen muchos problemas nuevos que no suelen estar presentes en otro tipo de programas. Con el objetivo de establecer una visión global de la problemática asociada a una interfaz de usuario, queremos determinar qué cosas deben tenerse en cuenta para producir una interfaz de usuario de calidad.

    + +

    Dividiremos las actividades de una interfaz de usuario en dos grandes grupos. El primero de ellos plantea un modelo de ciclo de interacción, es decir, el conjunto de actividades que suelen ocurrir en cada interacción con el usuario, en secuencia:

    + +
      +
    • Mostrar al usuario las distintas acciones que puede realizar (por ejemplo mediante un menú, botones, etc)
    • +
    • Permitir al usuario iniciar una nueva tarea o caso de uso.
    • +
    • Permitir al usuario ingresar información asociada a la tarea que desea realizar.
    • +
    • Transformar la información ingresada por el usuario al formato en el cual la aplicación los puede manipular internamente.
    • +
    • Actualizar el modelo de dominio con la información recibida.
    • +
    • Validar la información ingresada por el usuario. Suele haber tres puntos distintos de validación: +
        +
      • Previa a la transformación.
      • +
      • Posterior a la transformación y previa a la actualización del modelo.
      • +
      • Luego de actualizado el modelo.
      • +
      +
    • +
    • Ejecutar de una acción de dominio con la información recibida.
    • +
    • Manejar y presentar los errores si los hubiera.
    • +
    • Seleccionar la siguiente vista que se presentará al usuario y la información a mostrar en la nueva vista (por ejemplo, filtrado y/o proyección).
    • +
    • Transformar los resultados al formato en que pueden ser presentados al usuario.
    • +
    + +

    En forma transversal a este circuito básico se presenta un segundo conjunto de actividades, que no depende de un flujo de interacción sino que se entremezcla con el primero:

    + +
      +
    • Navegación de la aplicación entre las diferentes acciones que permite realizar
    • +
    • Manejo de transacciones, concepto de transacción desde el punto de vista de la aplicación
    • +
    • Manejo de la sesión de usuario, es decir, en el contexto de una aplicación multiusuario, la información relativa a la actividad de cada uno de los usuarios
    • +
    • Internacionalización
    • +
    • Distintas formas de verificación
    • +
    + + + +

    Criterios de calidad

    + +

    Con respecto a la construcción

    + +
      +
    • Consistencia, robustez.
    • +
    • Simplicidad, claridad.
    • +
    • Desacoplamiento entre dominio y UI
    • +
    • Desacoplamiento entre lógica y tecnología
    • +
    • Testeabilidad o verificabilidad.
    • +
    + + + +

    Con respecto a la usabilidad

    + +
      +
    • Claridad
    • +
    • Consistencia.
    • +
    • Riqueza (richness)
    • +
    • Feedback
    • +
    • Perfomance y percepción de performance.
    • +
    • Intuitividad, autoaprendizaje.
    • +
    + + + +

    Links relacionados

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-mvcpesado-formas-de-vincular-una-vista-con-el-modelo-de-dominio.html b/wiki/articles/ui-mvcpesado-formas-de-vincular-una-vista-con-el-modelo-de-dominio.html new file mode 100644 index 0000000000..78e67819f8 --- /dev/null +++ b/wiki/articles/ui-mvcpesado-formas-de-vincular-una-vista-con-el-modelo-de-dominio.html @@ -0,0 +1,459 @@ + + + + + + + + + + + Formas de vincular una vista con el modelo de dominio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Formas de vincular una vista con el modelo de dominio +

    +
    + + + + + +
    +

    Interacciones entre vista y modelo

    + +

    Dado que el objetivo de la interfaz de usuario es permitir la interacción con el modelo de dominio, cada uno de los elementos que conforman la interfaz de usuario tendrá como tarea alguna parte de esta interacción, ya sea mostrar al usuario una porción del modelo de dominio, o bien permitirle realizar acciones que lo modifiquen.

    + +

    Una forma simple de ordenar una interfaz de usuario es considerar que cada vista (que puede ser una ventana, una página o bien una porción bien delimitada de una vista más grande) tiene como responsabilidad interactuar con un único objeto de dominio. A este objeto de dominio lo denominaremos modelo de la vista.

    + +

    Desde esa premisa básica podemos imaginar que cada vez que haya un control editable en una vista, ese control estará editando algún atributo del modelo. Luego, las modificaciones que realicemos sobre estos controles editables, de alguna manera deberán ser impactadas sobre los atributos asociados. Al componente de software que toma la responsabilidad de impactar esos cambios lo denominamos controller.

    + +

    Los mecanismos para trasladar o impactar una modificación hecha por el usuario sobre cualquier control editable se pueden dividir en dos grandes grupos:

    + +
      +
    • Vinculación indirecta o manual
    • +
    • Vinculación directa o automática (binding).
    • +
    + + + +

    Vinculación indirecta

    + +

    En este tipo de estrategias los controles editables de la UI toman la responsabilidad de almacenar los valores que va ingresando el usuario a la espera de un evento que dispare la ejecución de la operación (en aplicaciones web este evento suele ser el submit de un formulario HTTP).

    + +

    Naturalmente, ante esta disociación, el objeto de dominio asociado no se ve afectado por las acciones del usuario hasta que no se produzca el evento antes mencionado. En el momento que se produce el submit, el controller deberá tomar la responsabilidad de leer todos los valores del formulario de los controles en los que fueron almacenados y recién ahí impactarlos en el modelo de dominio.

    + +

    De esta forma, cualquier validación o modificación dinámica de los valores en la vista deberá ser realizada sin la intervención del dominio o bien esperar hasta el momento del submit para poder llevarse a cabo. Esto incluye a muchos de los comportamientos denominados ricos de una UI, por ejemplo:

    + +
      +
    • Validaciones realizadas a medida que se cargan los datos en un formulario
    • +
    • Valores que dependen unos de otros (un caso típico: combos anidados).
    • +
    • Controles que se habilitan o deshabilitan dependiendo de los demás valores ingresados.
    • +
    + +

    La principal desventaja de este esquema radica en la no-intervención del modelo de dominio durante la interacción con el usuario, lo que impide aprovechar toda la lógica que contenga este objeto, que deberá tomar uno de dos caminos:

    + +
      +
    • Esperar al momento de submit para intervenir, con lo cual se pierden muchas de las posibilidades de UI rica enunciadas en la enumeración anterior.
    • +
    • Duplicar la lógica ya contenida en el modelo de dominio, replicándola en la interfaz de usuario de forma de poder realizar validaciones y otros comportamientos dinámicos basándose en el contenido de los controles.
    • +
    + +

    La primera de las opciones produce una limitación en las posibilidades que la UI le puede brindar al usuario, haciéndolo en muchos casos inviable o en otros perdiendo calidad en la UI. La segunda produce una duplicación de la lógica que podemos analizar desde dos perspectivas distintas.

    + +

    Por un lado, toda duplicación de código genera una potencial inconsistencia ante la posibilidad de que una de las dos partes se modifique quedando la otra desactualizada.

    + +

    Por el otro, la lógica propia del dominio metida dentro de la interfaz de usuario resulta mucho más incómoda de programar ya que deberemos adaptarnos a las restricciones tecnológicas de componentes que están diseñados prioritariamente para la interacción con el usuario. Como un ejemplo de las dificultades que aparecen, podemos mencionar que en lugar de tener la información necesaria almacenada en variables que tengan un tipo y toda la potencia de nuestro lenguaje de elección, deberemos tener los valores contenidos en controles, en muchos casos sin poder exigir que sean de un tipo determinado. Y entonces lo que para nosotros en el dominio es un número o una fecha en la UI será un String o lo que para nosotros es una referencia a otro objeto de dominio en la UI será un código (String) o un índice numérico en una lista.

    + +

    Naturalmente todas estas restricciones hacen al código más complejo y más propenso a errores, lo que nos lleva a evaluar la siguiente alternativa.

    + + + +

    Binding

    + +

    En este esquema, lo que se buscará es automatizar el pasaje de información entre la vista y el dominio. Es decir, se proveerá una descripción (declarativa) de la vinculación entre los componentes visuales y el modelo de dominio para que un componente genérico se ocupe de mantenerlos mutuamente sincronizados.

    + +

    A esta descripción de la vinculación entre ambos la solemos llamar binding y puede incluir entre otras cosas:

    + +
      +
    • Un mapeo entre un componente visual y un elemento del dominio, típicamente cada control de la vista estará asociado a un atributo de un objeto de domino.
    • +
    • Conversiones a realizar (por ejemplo si el valor a ingresar es una fecha y se ingresa desde la UI como texto, deberá proveerse el formato esperado y la lógica para convertir de ese formato a la representación interna de fechas que use el modelo de dominio).
    • +
    • Validaciones a realizar (dado que uno de los objetivos es aprovechar la lógica del modelo de dominio, normalmente las validaciones -salvo las propias de la conversión- serán delegadas en el modelo de dominio y por lo tanto la descripción de la validación consistirá en algún mecanismo para indicar qué consulta realizar sobre el dominio para poder efectuar la validación en cuestión).
    • +
    + +

    Esta estrategia busca fundamentalmente dos objetivos:

    + +
      +
    • Simplificar la sincronización entre ambas partes de la aplicación, basándose en componentes reutilizables.
    • +
    • Aprovechar la lógica contenida en el modelo del dominio para tomar acciones durante su propia edición.
    • +
    + +

    El segundo de estos objetivos es el que suele proponer a veces algunas dificultades, ya que para aprovechar la lógica se necesita impactar las modificaciones realizadas sobre la UI directamente sobre el objeto de dominio. En los casos de aplicaciones que tienen un comportamiento transaccional desde el punto de vista del usuario, esta acción directa sobre el dominio implica algún mecanismo para garantizar que en caso de cancelar la operación el objeto queda sin cambios, en su estado original antes de comenzar.

    + +

    Adicionalmente esta fuerte vinculación entre la vista y el dominio nos puede presentar dificultades si la vista tiene requerimientos que no son fácilmente atribuibles a un objeto del dominio, es decir, comportamiento específico de la vista. Ejemplos de comportamiento propios de la vista podrían ser paginar una grilla o dividir la información del objeto entre múltiples viñetas o tabs.

    + +

    Se necesitan entonces herramientas para manejar el nivel de acoplamiento entre la vista y el modelo de dominio, tanto por cuestiones de transaccionalidad como para poder asociar comportamiento no dependiente del dominio.

    + + + +

    Binding transaccional

    + +

    Citamos a continuación algunos de los mecanismos utilizados para desvincular el dominio de la vista para proveer a nuestra aplicación de un comportamiento transaccional:

    + +

    Aprovechamiento de la transaccionalidad de la persistencia

    + +

    Es frecuente encontrar aplicaciones donde la transaccionalidad está delegada en el mecanismo persistente, con frecuencia una base de datos relacional. Si el modelo de dominio de la aplicación es persistido en un mecanismo con soporte transaccional y además el ciclo de vida de los componentes de dominio está dominado por la persistencia (es decir, el objeto de dominio dura en memoria sólo durante una transacción y luego es descartado), entonces simplemente cancelando la transacción de persistencia se logra descartar los cambios realizados al modelo de dominio. Esta estrategia es muchas veces la más simple, y si bien tiene algunas limitaciones técnicas, es una de las más utilizadas.

    + +

    Postergación del binding mediante copias o wrappers

    + +

    Esta estrategia se basa en bindear la vista contra un objeto que no sea exactamente el dominio, para luego volcar los datos sobre el dominio en un paso posterior (probablemente en el submit). Esto permite garantizar que el dominio no se verá modificado hasta finalizar la acción del usuario, al mismo tiempo que trabajar el comportamiento dinámico de la vista sobre un objeto independiente de la tecnología de presentación. De esta manera, esta estrategia presenta una alternativa intermedia entre una vinculación manual y una automática.

    + +

    Existen dos variantes a esta estrategia. La primera de ellas es utilizar una copia del objeto de dominio a editarse, que luego deberá reemplazar al original en el dominio o bien trasvasar la información de un objeto a otro. La ventaja de esta estrategia es que permite reutilizar toda la lógica propia del objeto de dominio. El problema es que cuando se editan varios objetos relacionados desde la misma vista, impactar luego los cambios en el dominio puede resultar complejo.

    + +

    La segunda variante es utilizar un wrapper u otro objeto que no sea de la misma clase que el original. Lo interesante de esta técnica es que provee un mayor desacoplamiento entre vista y modelo (ver modelo de aplicación en el apartado siguiente). La desventaja es que obliga a duplicar la información del objeto original en este nuevo objeto (Al menos en un lenguaje basado en clases, en lenguajes con mecanismos de herencia más flexibles esta problemática puede ser resuelta de otras maneras, como mixins o traits. Lamentablemente, la mayoría de los lenguajes más populares hoy en día no proveen este tipo de mecanismos.)

    + +

    Transaccionalidad a nivel de dominio

    + +

    Otra posibilidad es permitir que los objetos de dominio manejen la transaccionalidad, es decir, permitir que sean modificados y, en caso de ser necesario, delegar en ellos mismos la responsabilidad de volver atrás los cambios cancelados por el usuario. Esto puede ser hecho manualmente (aunque puede resultar engorroso) o de forma automática, por ejemplo mediante aspectos.

    + +

    Comportamiento a nivel de vista

    + +

    A veces es necesario tener comportamiento en la vista que no es atribuible a ningún objeto de dominio. En ese caso algunas de las estrategias posibles son:

    + +

    Modelo de aplicación

    + +

    Llamamos modelo de aplicación a un objeto que tiene lógica que no es atribuible a un objeto de dominio, sin embargo es independiente de la tecnología, por lo tanto podemos considerarlo modelo. Un objeto de estas características nos provee de un espacio en donde colocar lógica utilizando las mismas herramientas del dominio pero sin tener que restringirnos a las limitaciones que solemos establecer sobre los objetos de domino.

    + +

    Típicamente los casos de uso complejos de una aplicación tendrán un modelo de este tipo que contemple la lógica necesaria para llevarlos a cabo. Pueden tener tanto lógica de navegación como de visualización, aunque en algunos casos también se decide separar ambos tipos de lógica.

    + +

    Value Models

    + +

    Otra forma de desacoplar la vista y el modelo es proveyendo un almacenamiento intermedio para cada control, que guarda el valor manejado por el control hasta el momento del submit, en el cual será volcado al modelo de dominio. Al objeto que contiene el valor durante ese tiempo se lo denomina ValueModel y la principal diferencia con la estrategia anterior es que en ese caso se tenía un único intermediario para toda la vista, mientras que ahora tenemos un intermediario por cada control.

    + +

    Un ValueModel provee de la posibilidad de definir trasnformaciones y validaciones a cada control. Una ventaja importante de este mecanismo es que provee de una forma sencilla de reutilizar la lógica de transformación y validación.

    + +

    Por otro lado, la atomización de estos objetos dificulta la posibilidad de establecer lógica sobre este modelo que dependa de más de uno de los controles de la vista.

    + +

    En los casos en que la relación entre la vista y el modelo de dominio es muy lejana, una solución posible es descartar el binding y pasar a una estrategia de interacción manual entre vista y dominio, aunque, claro, eso implica perder parte de las ventajas de automatizar este comportamiento.

    + + + +

    Links relacionados

    + + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-mvcpesado-intro-mvc.html b/wiki/articles/ui-mvcpesado-intro-mvc.html new file mode 100644 index 0000000000..26f9a8ca0a --- /dev/null +++ b/wiki/articles/ui-mvcpesado-intro-mvc.html @@ -0,0 +1,461 @@ + + + + + + + + + + + Intro a MVC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Intro a MVC +

    +
    + + + + + +
    +

    Qué necesitamos para construir una UI

    + +

    Vamos a armar una lista de cosas que necesitamos para poder desarrollar una aplicación que tenga interfaz de usuario. Sobre algunas (en negrita) vamos a hablar en este momento, las otras irán apareciendo próximamente:

    + +
      +
    • Elementos gráficos / controles / widgets.
    • +
    • Layout o forma de organizar visualmente los widgets.
    • +
    • Binding (de atributos y de acciones).
    • +
    • Navegación (cómo es el flujo de una vista a otra y cómo se pasa información desde una vista a otra).
    • +
    • Manejo del estado conversacional de los datos que se cargan en la vista.
    • +
    + +

    Elementos gráficos o widgets (los controles)

    + +

    Podemos clasificar a los controles de la siguiente manera:

    + +
      +
    • container: agrupan otros controles, siguiendo el pattern Composite. Son el formulario, el frame, el groupbox, las solapas, etc.
    • +
    • value holders o los que permiten ingresar un valor: calendars, textbox, checkbox, combo,- radiobutton, etc.
    • +
    • que trabajan sobre conjunto de datos: la grilla, el listbox, treeview (para mostrar - información jerárquica), etc.
    • +
    • que disparan acciones: button, link
    • +
    + +

    Layout

    + +

    Cómo disponer esos elementos gráficos en la pantalla:

    + +

    + layout definido en forma visual +

    + +

    Eso suele generar código por abajo que está pensado en píxeles x@y (un punto) sobre la pantalla. Tener herramientas visuales WYSIWYG nos ayuda a no tener que explicar “quiero el botón acá”, armar la pantalla con una toolbar de controles es más fácil que tener que explicarlo programando, resulta más intuitivo. Por otra parte lo visual me ata, la mayoría de las decisiones que tomo al construir la pantalla no quedan registradas en ningún lado. Yo se que estoy alineando los controles pero no digo en ningún lado alineado a qué porcentaje: ¿es un 40% del ancho de la pantalla? Y… “más o menos”. Si tengo que agregar un campo nuevo a una pantalla con una herramienta visual tengo que volver a acomodar toda la pantalla, tirar para “abajo” los controles que ya están, volver a respetar el margen, etc. etc.

    + +

    De la misma manera cada vez que me siento a diseñar una pantalla nueva tengo que tener en cuenta todas estas definiciones que no están escritas (o pueden estar en un documento que yo me tengo que encargar de respetar: estilos de fuente, disposición de controles, orden de la botonera: Cancelar primero y Aceptar después, o al revés, etc.) Esto ocurre aun cuando las herramientas visuales me generen código en Java (o bien generen código propietario que luego se interpreta para armar la parte visual), porque el proceso de creación de la pantalla queda en la cabeza del que la desarrolla…

    + +

    layout definido en forma programática

    + +

    Cuando en lugar de tener una herramienta visual lo codifico me puede pasar lo mismo si no encuentro formas de decir:

    + +
      +
    • “los labels siempre se alinean a la derecha”,
    • +
    • “todos los controles de carga de datos del formulario ocupan 70% de la pantalla”,
    • +
    • “la botonera se arma siempre: Cancelar, Aceptar y algunos botones configurables”, etc.
    • +
    + +

    ¿Qué buscamos al definir el layout de la interfaz? 1) que yo no hable en absoluto y trabaje sobre ideas relativas. 2) pero además, yo tengo que poder decir de alguna manera y en un solo lugar “esto va abajo” , “esto va arriba”, “el botón Cancelar va a la izquierda del Aceptar”, “todos los botones se agrupan abajo del formulario y centrado”, de esa manera es más fácil después alinear las botoneras de todas las pantallas a la izquierda, o bien cambiar el layout de la botonera (por ejemplo para que los botones aparezcan a la derecha de la pantalla uno abajo del otro).

    + +

    + image +

    + +

    Lo que está dentro de la nube debería “reificarse” (llevar esa abstracción al código, esa abstracción es el Layout).

    + +

    Binding

    + +

    Lo que hace que la pantalla tenga sentido es que los elementos gráficos estén relacionados con el dominio. O sea, hay una relación entre los elementos gráficos y los de dominio: muchos elementos gráficos son representaciones visuales de elementos de mi dominio,

    + +
      +
    • que pueden mostrar información o permitir editarla (la fecha de un alquiler, el nombre de un actor),
    • +
    • o disparar acciones (el alta de un socio, la búsqueda de películas según un criterio, etc.)
    • +
    + +

    Intro a MVC

    + +

    El binding relaciona parte visual y la información que está relacionada. A la primera se la suele llamar vista, a la segunda modelo.

    + +

    El binding se puede dar de dos maneras:

    + +
      +
    • la vista es la única que actualiza el modelo V –> M. Ejemplo: un procesador de texto. Entonces es claro que el flujo va solamente de pantalla a modelo.
    • +
    • la vista actualiza el modelo o el modelo puede actualizarse desde otro contexto y tonces el modelo dispara la notificación a la vista. V <–> M. La segunda visión (la notificación en ambos sentidos entre modelo y vista) es la que da sentido a separar modelo de vista para poder reutilizar el modelo en más de un contexto (ej: si queremos tener una pantalla de Alta de un Socio para un videoclub o bien subir un Excel con un conjunto de socios y que dicha carga sea masiva)
    • +
    + +

    Vamos a darle la responsabilidad a alguien (que llamaremos controller) para que se encargue de manejar el binding de atributos y acciones en forma bidireccional (o sea: hacia la vista y hacia el dominio). Para eso vamos a trabajar de la siguiente manera: la vista se va a registrar como interesada en el modelo. Entonces cada vez que alguien actualice el modelo, se va a disparar una notificación hacia determinados interesados (esta sería una implementación del Observer pattern).

    + +

    + mvc +

    + +

    En definitiva, si la aplicación está bien construida lo que pasa es:

    + +
      +
    1. un cambio en la vista dispara un mensaje a un objeto de negocio
    2. +
    3. el negocio modifica su estado interno y dispara la notificación a la vista (en realidad, a todos los interesados, la vista es sólo uno más)
    4. +
    5. la vista se actualiza con la información del objeto de negocio (esto puede significar que ahora un campo esté deshabilitado o que mostremos el socio en color azul porque ya no debe plata)
    6. +
    + +

    O sea: vista y negocio están sincronizados todo el tiempo, cada uno sabe qué tiene que hacer:

    + +
      +
    • el negocio sabe su lógica
    • +
    • la vista sabe cómo mostrar la información del negocio.
    • +
    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-mvcpesado-mmvc.html b/wiki/articles/ui-mvcpesado-mmvc.html new file mode 100644 index 0000000000..b6cab0353a --- /dev/null +++ b/wiki/articles/ui-mvcpesado-mmvc.html @@ -0,0 +1,416 @@ + + + + + + + + + + + Application model. Extendiendo el MVC. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Application model. Extendiendo el MVC. +

    +
    + + + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Introducción

    + +

    En Arena cada vista requiere un modelo. Esto implica encontrar una abstracción que pueda cumplir esa responsabilidad. Algunas pantallas como el conversor de millas a kilómetros utilizan un objeto de dominio como modelo; pero cuando la complejidad de la interacción con el usuario crece, no nos alcanza con tratar de resolverlo con un objeto de dominio como Celular, Socio o Película.

    + +

    Entonces nuestro objetivo es tener un objeto que sea totalmente independiente de la tecnología, pero que tenga todo el comportamiento necesario de la aplicación. Es la representación del comportamiento global de la aplicación sin la componente tecnológica.

    + +

    Algunos ejemplos

    + +

    Una pantalla de búsqueda de clientes de una compañía que vende celulares:

    + +

    + image +

    + +

    Una ventana para crear un pedido, que selecciona cliente y producto (y también permite darlos de alta):

    + +

    + image +

    + +

    E incluso podemos pensar que una pantalla de alta o edición puede manejarse con un application model, esto permite no tener una referencia extra para conocer al home o repositorio:

    + +

    Objetivo

    + +

    Consideramos importante la separación entre los componentes de la aplicación que dependen de la tecnología (vista, controller) y los que no (modelos de aplicación o de dominio). Y el application model nos da la herramienta para lograr eso.

    + +

    Esta estrategia nos permite:

    + +
      +
    • Tener un modelo rico, en el cual poder programar y diseñar libremente, sin dependencias tecnológicas.
    • +
    • Por ser independientes de la vista pueden ser testeados unitariamente con herramientas sencillas (las que ya conocen, sin la complejidad de las herramientas de testeo automático para interfaces de usuario, vean para eso los tests del ejemplo de los celulares).
    • +
    • Por adaptarse a las necesidades de la vista, simplifican el mapeo que realizan los controllers.
    • +
    + +

    El application model funciona como buffer entre la vista y el modelo de dominio y nos va a permitir construir esa parte de la aplicación programando con objetos y en nuestro lenguaje de preferencia, en lugar de tener que adaptarse a un framework, tecnología o lenguaje que no tiene la misma potencia. Algunas variantes de ese concepto se pueden ver en el artículo formas de vincular una vista con el modelo de dominio.

    + +

    Objeto de dominio vs. application model

    + +

    Podemos encontrar dos diferencias importantes:

    + +
      +
    • El application model tiene otra naturaleza en cuanto a la forma en que aparece, no está (a priori) entre los conceptos que maneja el usuario.
    • +
    • Tiene otro ciclo de vida. Los objetos del dominio se crean, se guardan (utilizando probablemente un repositorio persistente), luego se pueden consultar, modificar, etc. En cambio los objetos de aplicación se usan una sola vez, suelen tener el estado conversacional entre un usuario y la aplicación, representan un caso de uso.
    • +
    + +

    Esquema MMVC

    + +

    El objeto Application Model da origen al esquema MMVC [1]:

    + +
      +
    • V - Vista: la pantalla *Window
    • +
    • C - Controller: adapta la vista con el modelo, en el caso de Arena son muchos objetos con responsabilidades bien definidas que se relacionan con el application model: binders, transformers, filters, etc.
    • +
    • M - Modelo de la vista/modelo de aplicación/application model: modela al caso de uso, mantiene simple el binding con la vista
    • +
    • M - Modelo de dominio
    • +
    + +

    + image +

    + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-mvcpesado-navegacion.html b/wiki/articles/ui-mvcpesado-navegacion.html new file mode 100644 index 0000000000..31ebbcac93 --- /dev/null +++ b/wiki/articles/ui-mvcpesado-navegacion.html @@ -0,0 +1,426 @@ + + + + + + + + + + + Navegación + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Navegación +

    +
    + + + + + +
    +

    Introducción

    + +

    La navegación es un subconcepto de una incumbencia más general de nuestra aplicación, y en particular de nuestra interfaz de usuario: la interacción. Toda acción del usuario sobre la interfaz es una interacción. Navegación se refiere en particular a esas interacciones que el usuario realizará para poder llevar acabo diferentes tareas. En general serán todas las interacciones relacionadas con el ciclo de vida de una tarea:

    + +
      +
    • cómo iniciar una tarea
    • +
    • cómo terminar una tarea: +
        +
      • exitósamente
      • +
      • cancelándola
      • +
      +
    • +
    • ¿será posible realizar tareas en simultáneo?
    • +
    • ¿podrá el usuario anidar tareas (realizar una subtarea mientras aún sigue con la tarea más general)?
    • +
    + +

    Cómo verán aquí, tanto nombrar el concepto de tarea les dará la idea de que es un concepto importante, ya que la navegación se define en base a ella. Pero entonces bajémoslo a algo concreto, ¿qué sería una tarea?

    + +

    Tarea / Caso de uso

    + +

    Nos referimos a tarea aquí como una unidad de trabajo que comienza y realiza un usuario sobre el dominio.

    + +

    Por ejemplo, en un sistema de gestión de un videoclub:

    + +
      +
    • Crear un nuevo usuario
    • +
    • Alquilar una película
    • +
    • Buscar un usuario
    • +
    • Eliminar un usuario
    • +
    • Crear una nueva película
    • +
    • Buscar una película
    • +
    • etc.
    • +
    + +

    Esta definición tiene cierta similitud con la idea de caso de uso del análisis de requerimientos. Por eso a veces se utilizan ambos términos intercambiablemente.

    + +

    Pero entonces, ¿cómo se relacionan las tareas con la UI?

    + +

    Relación entre una tarea y los elementos de UI

    + +

    La relación entre las tareas y la UI es justamente la navegación. Esta navegación, o su implementación va a depender de varios factores:

    + +
      +
    • La arquitectura: por ejemplo, +
        +
      • Aplicación standalone de escritorio
      • +
      • Aplicación web distribuida
      • +
      • Aplicación móvil distribuida
      • +
      +
    • +
    • Los dispositivos: +
        +
      • PC
      • +
      • Handhelds: PDA, Palm
      • +
      • Mobile: android
      • +
      • Dispositivos dedicados o de ciertas industrias particulares
      • +
      +
    • +
    • La tecnología que estemos usando: léase el framework que estemos usando. Las capacidades que nos brinde y sus limitaciones. Por ejemplo, Arena no les permite acceder a los controles propiamente dichos (ejemplo, acceder al texto actual de un TextBox, o a su propiedad borderWith).
    • +
    • Los requerimientos de usuario: +
        +
      • La interfaz de usuario es un elemento más de nuestro sistema, y como todo el usuario/cliente puede tener una idea preconcebida de lo que quiere de ella. De hecho, la interfaz es uno de los puntos centrales ya que es justamente la cara visible para el usuario.
      • +
      +
    • +
    + +

    Así como hemos visto previamente cómo vincular nuestro dominio con la interfaz de usuario (a través de bindings, por citar un ejemplo), la manera de implementar una tarea y su navegación va a depender de todos estos factores que nombramos.

    + +

    Un ejemplo concreto

    + +

    Si estamos en una aplicación de facturación minorista de cualquier negocio, pensemos la vista del caso de uso “Crear factura”, y en particular cómo sería la navegación para seleccionar al cliente. Tenemos varias opciones:

    + +
      +
    • el cliente se selecciona en un campo de autocompletado. El usuario no necesita salir de la página.
    • +
    • el cliente se selecciona navegando una búsqueda por diferentes criterios, lo que implica ir hacia una vista nueva (una ventana de diálogo).
    • +
    • adicionalmente, ¿qué estrategia adoptamos si se trata de un cliente nuevo? ¿necesitamos salir de la vista “Crear factura” y navegar a la vista del caso de uso “Crear cliente” o podemos cargar datos mínimos del cliente sin tener que perder el foco en lo que venimos haciendo? ¿la vista que carga el cliente está como una ventana de diálogo o está embebida en el caso de uso actual?
    • +
    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-mvcpesado-transaccion.html b/wiki/articles/ui-mvcpesado-transaccion.html new file mode 100644 index 0000000000..b0a89e4aab --- /dev/null +++ b/wiki/articles/ui-mvcpesado-transaccion.html @@ -0,0 +1,416 @@ + + + + + + + + + + + Arena. Manejo de transacciones. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Arena. Manejo de transacciones. +

    +
    + + + + + +
    +

    Introducción

    + +

    Si estamos modificando los datos de una entidad, es frecuente hacerlo en un formulario que tiene dos acciones posibles: aceptar o cancelar los cambios.

    + +

    + edicion-1 +

    + +

    Cuando la UI tiene binding, cualquier modificación que haga el usuario impacta directamente en el modelo. ¿Qué alternativa tenemos entonces para volver atrás los cambios si el usuario desiste la acción?

    + +

    Sincronización mediante repositorios persistentes

    + +

    Si estamos en un esquema distribuido, una opción puede ser que nuestro repositorio trabaje con un medio persistente, con dos objetivos:

    + +
      +
    • sincronizar la información de las distintas sesiones de usuario
    • +
    • proveer un ambiente donde las operaciones son transaccionales (todas las actualizaciones ocurren al mismo tiempo o si falla alguna se cancelan las restantes)
    • +
    + +

    En ese caso cuando el usuario presiona el botón Aceptar se envía un mensaje al repo para que actualice el objeto del formulario, caso contrario el repo no recibirá ninguna notificación. Cuando un usuario en otra VM diferente quiere actualizar el mismo cliente, el objeto repositorio toma la información del medio persistente para recrear los datos del cliente actualizados. El medio persistente actúa como “la única fuente de verdad”, y mientras que los objetos que están en el ambiente son simplemente un buffer o estado temporal antes de ser almacenados en el medio.

    + +

    + two_users +

    + +

    Trabajo en una única VM con binding

    + +

    Si en nuestra aplicación el repositorio considera la VM de objetos como la single source of truth, el mecanismo de binding puede traer efectos colaterales: cada vez que el usuario modifique el nombre, eso tiene un impacto inmediato en el modelo y tenemos que pensar qué debemos hacer si el usuario quiere cancelar la operación de edición para que efectivamente se deshagan los cambios.

    + +

    + single_vm +

    + +

    Opción 1: Manejo manual de los cambios

    + +

    La primera alternativa consiste en generar una copia del objeto original y asociarlo como modelo de nuestra ventana de modificación.

    + +
      +
    • al cancelar no necesitamos hacer nada, porque los cambios se hicieron contra un objeto que no está asociado al repositorio
    • +
    • al aceptar, pisamos el objeto original (referenciado desde el repositorio) con los nuevos atributos del objeto copia.
    • +
    + +

    + copy +

    + +

    Opción 2: Elementos transaccionales de Arena

    + +

    Arena propone un esquema para no tener que resolver esto manualmente:

    + +
      +
    • todos los objetos que sean modelos de una vista se anotan como @Transactional, para indicar a Arena que participa dentro de una transaccción. Esto incluye a los objetos de dominio y también a los objetos que modelan un caso de uso (que llamamos application model, se explican en el formulario de búsqueda).
    • +
    • como además queremos que disparen notificaciones a las vistas y demás interesados, debemos mantener la annotation @Observable
    • +
    • también existe la anotación @TransactionalAndObservable (cualquiera de las dos variantes funciona exactamente igual)
    • +
    • la vista debe heredar de TransactionalDialog<T>
    • +
    + +

    Y con esto nos alcanza, Arena utiliza la vista para delimitar el alcance de una transacción: cuando el usuario presiona el botón Aceptar se finaliza (commit). En caso de error, o de presionar el botón Cancelar, la transacción se deshace (rollback), y los cambios se pierden.

    + +

    El lector interesado puede consultar el ejemplo de los celulares que trabaja automáticamente la transacción.

    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-mvcpesado-validaciones-errores.html b/wiki/articles/ui-mvcpesado-validaciones-errores.html new file mode 100644 index 0000000000..2ed75c4490 --- /dev/null +++ b/wiki/articles/ui-mvcpesado-validaciones-errores.html @@ -0,0 +1,908 @@ + + + + + + + + + + + Validaciones y manejo de errores en la UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Validaciones y manejo de errores en la UI +

    +
    + + + + + +
    +

    Podemos ver un repaso del tema excepciones en esta página

    + +

    Introducción

    + +

    Consideremos el ejemplo de los clientes de una empresa de celulares, donde tenemos un formulario que permite ingresar

    + +
      +
    • nombre del cliente
    • +
    • número de celular
    • +
    • modelo de celular
    • +
    • si quiere recibir el resumen de cuenta en el domicilio
    • +
    + +

    Validaciones a implementar

    + +
      +
    1. El número debe contener sólo dígitos numéricos
    2. +
    3. El modelo de celular debe ser un modelo válido
    4. +
    5. Los números de celular deben ser mayores a 1000
    6. +
    7. No puede ingresarse el mismo número de teléfono para dos clientes diferentes
    8. +
    9. Algunos modelos de celular exigen que sus clientes reciban el resumen de cuenta en su domicilio
    10. +
    + +

    ¿Qué hacemos en cada caso? ¿Quién es responsable de cada validación?

    + +

    Momentos de la validación

    + +

    El número debe contener sólo dígitos numéricos

    + +

    Si el objeto de dominio Celular define el número de teléfono como un Integer, no es posible hacer

    + +
    +
    +
    +      celular.numero = "A"
    +
    +    
    +
    +
    + +

    eso no compila. Pero la UI podría tener un cuadro de texto que permita ingresar caracteres alfanuméricos: entonces tenemos que elegir cuál va a ser el comportamiento del sistema

    + +
      +
    1. permitir ingresar caracteres inválidos pero mostrar un mensaje de error: en Arena esto lo hace por defecto el controller que adapta lo que el usuario carga a lo que el dominio necesita. El panel de errores (ErrorsPanel) captura cualquier excepción que ocurra en la conversión, ya sea que lo incluyamos manualmente o por una ventana que herede de SimpleWindow.
    2. +
    3. podríamos pensar: ¿para qué dejamos que el usuario ingrese un caracter inválido si luego lo vamos a rechazar? La segunda variante consiste en definir un filtro que no permita que el usuario pueda ingresar caracteres alfabéticos si queremos que ingrese números. Para esto…
    4. +
    + +

    Opción 1: Definimos un filter

    + +

    Esta es la versión en lenguaje Java:

    + +
    +
    +
    +      new TextBox(form)
    +    .withFilter(new TextFilter {
    +        public boolean accept(TextInputEvent event) {
    +            return StringUtils.isNumeric(event.getPotentialTextResult());
    +        }
    +    })
    +    .bindValueToProperty(Celular.NUMERO);
    +
    +    
    +
    +
    + +

    La misma versión en lenguaje Xtend:

    + +
    +
    +
    +      new TextBox(form) => [
    +    withFilter [ event | event.potentialTextResult.matches("[0-9,.]*") ]
    +    bindValueToProperty("numero")
    +    width = 100
    +]
    +
    +    
    +
    +
    + +

    ¿Qué es el TextFilter dentro del MVC? El TextFilter es un controller, porque se comunica con el dominio (le manda un mensaje al modelo - en el caso de estar ok el input) y actúa sobre la vista (en la pantalla no aparece ese caracter, se filtra).

    + +

    Opción 2: Utilizamos un control específico para ingresar números

    + +

    Desde Arena 3.6.1 tenemos un control NumericField que se encarga de filtrar los caracteres alfabéticos:

    + +
    +
    +
    +      // Java
    +new NumericField(form).setWidth(150).bindValueToProperty("numero");
    +
    +    
    +
    +
    + +
    +
    +
    +      // Xtend
    +new NumericField(form) => [
    +    value <=> "numero"
    +    width = 100
    +]
    +
    +    
    +
    +
    + +

    Internamente está utilizando un Filter, lo importante es que tenemos una abstracción de alto nivel que está diciendo “quiero un control donde sólo se puedan cargar números”.

    + +

    Entonces la primera variante es impedir cualquier ingreso inválido por parte del usuario: Esto tiene como ventaja ser fail fast, evita ingresos incorrectos y esto para el usuario es más beneficioso.

    + +

    Otras formas de evitar acciones incorrectas

    + +

    Siguiendo la anterior linea de pensamiento, ¿debería dejar que el usuario presione el botón Aceptar, solo para mostarle un mensaje de error después? ¿no debería habilitar el botón Aceptar solamente cuando todos los controles se hayan cumplido satisfactoriamente?

    + +

    Aquí vemos que esta estrategia tiene un límite: en ciertos casos las validaciones del negocio pueden ser verdaderamente complejas como para poder dejarlas en forma explícita en la pantalla. Entonces el usuario sentirá una lógica frustración de no poder avanzar con el caso de uso cuando el botón Aceptar esté inhabilitado y no quede claro por qué. Una regla importante para la usabilidad de un sistema es que debe explicar claramente al usuario qué información no cumple las reglas de negocio y además cómo debe continuar para llegar al caso exitoso.

    + +

    Implementando las validaciones restantes

    + +

    El modelo de celular debe ser un modelo válido

    + +

    ¿El responsable es el celular? sí, si lo pensamos como un dato obligatorio, pero claramente participan

    + +
      +
    1. la UI que guía al usuario mostrándole un combo con las opciones válidas, el usuario no puede elegir un modelo inexistente, a lo sumo puede dejarlo vacío
    2. +
    3. si yo permito que el combo quede vacío, el dominio (el objeto celular) debería validar que el celular no deje en blanco el campo modelo. El form builder permite en sus opciones decirle “este combo no tiene la opción vacía”.
    4. +
    + +
    +
    +
    +      // Java
    +Selector<ModeloCelular> selector = new Selector<ModeloCelular>(form) //
    +     .allowNull(false);
    +
    +    
    +
    +
    + +
    +
    +
    +      // Xtend
    +new Selector<Modelo>(form) => [
    +     allowNull(false)
    +
    +    
    +
    +
    + +

    El tema es que al dar de alta un celular el binding es contra un atributo nulo, entonces el combo queda igualmente vacío. ¿Dónde voy a poner la validación del celular? En la clase Celular, un método validar() ¿qué va a devolver? void, o exception si hubo error… nada de códigos de error numéricos, como saben. Porque si todo sale bien sólo sigo enviando mensajes a los objetos que corresponden. Y si algo sale mal se que tengo que atrapar una excepción en la vista.

    + +

    Entonces no acoplo innecesariamente las validaciones del modelo a la vista. La pantalla de edición sólo tiene que saber que pueden ocurrir dos tipos de error posibles:

    + +
      +
    • errores de negocio: surgen de las restricciones que el negocio va poniendo (no podés ingresar un modelo inexistente, no podés poner caracteres alfabéticos en la línea del celular). Esto lo modelamos con una UserException.
    • +
    • errores de sistema: son errores propios de la programación, o errores generales del sistema (algo se rompió). Estos no los modelamos, simplemente ocurren: son los NullPointerException, OutOfMemoryError, etc. +Codificamos entonces el método validar:
    • +
    + +
    +
    +
    +      // Java
    +public void validar() {
    +   ...
    +   if (this.modeloCelular == null) {
    +      throw new UserException("Debe ingresar un modelo de celular");
    +   }
    +}
    +
    +    
    +
    +
    + +
    +
    +
    +      // Xtend
    +def void validar() {
    +    ...
    +    if (modeloCelular == null) {
    +        throw new UserException("Debe ingresar un modelo de celular")
    +    }
    +}
    +
    +    
    +
    +
    + +

    ¿Quién debe atrapar esta excepción que tira el negocio?

    + +

    Eso tiene que estar del lado de la tecnología de presentación: en la vista o más precisamente en el controller, allí debe estar el bloque try/catch para trabajar tanto los errores de negocio como los de sistema:

    + +
      +
    • si ocurre un error de usuario/negocio, el mensaje contiene información importante para el usuario. Entonces hay que mostrarle un cartel (o dejar una parte específica del panel para mostrar errores) con lo que contenga la propiedad message de la excepción de usuario/negocio
    • +
    • por el contrario, si el error se da dentro del programa, mostrar el mensaje de error al usuario le genera confusión: lo mejor que uno puede hacer es advertirle al usuario que hubo un error, que la operación que solicitó no va a poder completarse y sobre todo, registrar el problema para que un desarrollador lo analice luego.
    • +
    + +

    Los números de celular deben ser mayores a 1000

    + +

    Si ponemos la validación en el setter

    + +
    +
    +
    +      // Java
    +public void setNumero(Integer numero) {
    +    if (numero < MAX_NUMERO) {
    +        throw new UserException("El número de celular debe ser mayor a " + MAX_NUMERO);
    +    }
    +    this.numero = numero;
    +}
    +
    +    
    +
    +
    + +
    +
    +
    +      // Xtend
    +def void setNumero(Integer unNumero) {
    +    if (unNumero != null && unNumero.intValue() <= MAX_NUMERO) {
    +        throw new UserException("El número debe ser mayor a " + MAX_NUMERO)
    +    }
    +    this.numero = unNumero
    +}
    +
    +    
    +
    +
    + +

    eso tiene como consecuencia que tanto en la búsqueda como al editar un celular yo tenga que poner un número de celular mayor a 1000. ¿Tiene sentido? Y… en parte sí porque si yo no puedo ingresar un celular mayor a 1000 no tiene sentido que pueda buscar un celular menor a 1000, no lo voy a encontrar (en una aplicación comercial me reportaron en un caso de prueba que no debería poder buscar por CUIT si ese CUIT no es válido).

    + +

    Si ubicamos la pregunta en un método validar y lo llamamos en onClick del botón Aceptar…

    + +
    +
    +
    +      // Java
    +public void validar() {
    +    if (!this.ingresoNumero()) {
    +        throw new UserException("Debe ingresar número");
    +    }
    +    if (this.numero.intValue() <= MAX_NUMERO) {
    +        throw new UserException("El número debe ser mayor a " + MAX_NUMERO);
    +    }
    +    ...
    +
    +    
    +
    +
    + +
    +
    +
    +      // Xtend
    +def validar() {
    +    if (numero == null) {
    +        throw new UserException("Debe ingresar número")
    +    }
    +    if (numero.intValue() <= MAX_NUMERO) {
    +        throw new UserException("El número debe ser mayor a " + MAX_NUMERO)
    +    }
    +    ...
    +
    +    
    +
    +
    + +

    el efecto que tiene es que pude ingresar números menores a 1000 en la búsqueda pero no en la edición.

    + +

    O sea, cuando yo tuve que poner esta validación, dudé entre ponerlo en:

    + +
      +
    1. el setter del atributo número
    2. +
    3. el método validar de celular, que se dispara al presionar el botón aceptar.
    4. +
    + +

    Ahora, validar que el nombre y el número no sean nulos claramente no está bueno incorporarlo en el setter porque entonces la búsqueda me fuerza a escribir algo tanto en el nombre como en el número. Nuevamente aparece una tensión de fuerzas: la filosofía fail fast me dice que debería tirar error tan pronto como sea posible, eso tiene como consecuencia que a medida que estoy ingresando una fecha o un rango de valores estoy recibiendo continuos mensajes de error que distraen mi foco de atención. Por otra parte esperar a que un formulario con muchos campos se complete para validar produce una sensación frustrante al querer aceptar: “Falta xxx”, “Debe completar yyy”, “La fecha es inválida”, etc.

    + +

    ¿Cuál es la solución? No hay una única respuesta como se imaginarán,

    + +
      +
    • algunas validaciones irán en los filtros
    • +
    • otras pueden ir en los setters
    • +
    • otras deberán esperar su turno en la validación del formulario
    • +
    • y la estrategia resultante será una combinación de todas ellas
    • +
    + +

    No puede repetirse el mismo número de celular para dos clientes

    + +

    Esto no lo puedo validar en Celular, porque un objeto sólo tiene validaciones atómicas. Un celular no conoce a todos los otros celulares, me costaría mucho trabajo hacer que eso sucediera. Pero hay otro objeto que sí conoce a todos los celulares: el home/repositorio.

    + +

    Por suerte en la implementación del Repo default en Arena, el método create delega posibles validaciones en un “hook method” específico, que se llama validateCreate:

    + +

    En AbstractAutogeneratedIdRepo<T> donde T es un Celular (hereda de Entity):

    + +
    +
    +
    +      public void create(T object) {
    +    this.validateCreate(object);
    +    ...
    +
    +    
    +
    +
    + +

    Definimos la validación en RepositorioCelulares:

    + +
    +
    +
    +      // Java
    +@Override 
    +public void validateCreate(Celular celular) {
    +    celular.validar();
    +    validarClientesDuplicados(celular);
    +}
    +
    +public void validarClientesDuplicados(Celular celular) {
    +    int numero = celular.getNumero();
    +    if (!this.search(numero).isEmpty()) {
    +        throw new UserException("Ya existe un celular con el número: " + numero);
    +    }
    +}
    +
    +    
    +
    +
    + +
    +
    +
    +      // Xtend
    +override validateCreate(Celular celular) {
    +    celular.validar()
    +    validarClientesDuplicados(celular)
    +}
    + 
    +def void validarClientesDuplicados(Celular celular) {
    +    val numero = celular.numero
    +    if (!this.search(numero).isEmpty) {
    +        throw new UserException("Ya existe otro cliente con el mismo número")
    +    }
    +}
    +
    +    
    +
    +
    + +

    ¿Qué pasa en la modificación?

    + +
      +
    • Actualizar una colección en memoria es simplemente borrar el objeto anterior y agregar el objeto editado, eso está definido en CollectionBasedRepo.
    • +
    • Arena no definió un método validateUpdate() para incorporar validaciones. Esta limitación suele ser común al utilizar frameworks, eso no evita que podamos interceptar el mensaje update, de la siguiente manera:
    • +
    + +
    +
    +
    +      override update(Celular celular) {
    +    validarClientesDuplicados(celular)
    +    super.update(celular)
    +}
    +
    +    
    +
    +
    + +

    Al fin y al cabo estamos trabajando con objetos.

    + +

    ¿Y la validación cuándo se dispara? Cuando aceptamos el formulario, porque determinar si el número de celular se repite con otro tiene sentido cuando terminamos de definir el número, y además esa operación tiene un costo.

    + +

    Obligatoriedad de recibir resumen de cuenta en domicilio

    + +

    Cada celular pertenece a un modelo de celular que define si debe recibir el resumen de cuenta en domicilio. ¿Cómo afecta eso a la ventana de edición?

    + +
      +
    • Una opción es que la vista no sufra modificaciones: en el método validar chequeamos que el usuario haya cargado una configuración válida para el modelo de celular y recepción de resumen de cuenta en domicilio.
    • +
    • Pero para el usuario esta decisión puede resultar desconcertante: ¿qué modelo será el que me permita dejar destildado el check? Por eso para diseñar una buena UI necesitaríamos hacer algunas modificaciones: si el modelo de celular obliga a que el cliente reciba el resumen de cuenta, debería +
        +
      • automáticamente ponerse en true el flag recibeResumenCuenta para el cliente
      • +
      • deshabilitarse la opción de modificar el check
      • +
      +
    • +
    + +

    Entonces vemos que la validación original en el celular pierde sentido: la interfaz va guiando al usuario impidiendo que tome decisiones incorrectas y minimizando así las ventanas de error según las restricciones que impone el negocio. Eso no implica sacar la validación, pero sí tener en mente la famosa experiencia de usuario para anticiparnos a ingresos incorrectos.

    + +

    Aunque no siempre es posible evitar los mensajes de error, como hemos visto con la duplicidad de números de celular (no podemos saberlo sin consultar al repositorio), estas ideas de diseño en la UI mejoran notablemente su usabilidad.

    + +

    Algunas conclusiones

    + +

    Desventajas de las excepciones

    + +

    Como las excepciones cortan el flujo normal de envío de mensajes entre objetos, la contra de tirar una excepción por cada error de negocio es que no nos permite decirle al usuario todos los campos que tienen problemas (los errores van apareciendo de a uno). Por eso otra técnica es “recolectar” los errores y asociarlos a campos, de manera de tener un listado de mensajes de error donde cada uno está asociado a un campo que se ingresa en el formulario.

    + +

    Pop-ups y paneles de error

    + +

    Volviendo al ejemplo de los celulares, vemos que la validación tira User Exceptions:

    + +
    +
    +
    +      def void validar() {
    +      if (!this.ingresoNumero) {
    +            throw new UserException("Debe ingresar número")
    +      }
    +    ...
    +}
    +
    +    
    +
    +
    + +

    Lo mismo ocurre con validaciones que hacen los repos:

    + +
    +
    +
    +      private void validarClientesDuplicados(Celular celular) {
    +      val numero = celular.numero
    +      if (!this.search(numero).isEmpty) {
    +            throw new UserException("Ya existe un celular con el mismo número")
    +      }
    +}
    +
    +    
    +
    +
    + +

    Pero esa excepción no está atrapada en el método asociado al botón Aceptar de la pantalla de Edición.

    + +
    +
    +
    +      new Button(actions)
    +      .setCaption("Aceptar")
    +      .onClick [ | this.accept]
    +      .setAsDefault
    +      .disableOnError
    +
    +    
    +
    +
    + +

    ¿Cómo es entonces que funciona bien, que los errores se muestran con un popup?

    + +
      +
    • cada control de arena tiene un realidad abajo un builder que crea finalmente los objetos de la tecnología. En nuestro caso objetos swt + jface
    • +
    • por ejemplo, al crear un SimpleWindow nosotros estamos utilizando (sin saberlo) un JFaceWindowBuilder que le construye el ErrorViewer (esto no ocurre si nuestra ventana hereda de Window solamente)
    • +
    • Cuando se crea un botón, por ejemplo, y le seteamos un Action en el onClick, esta capa de Arena le agrega un listener (un observer) que envuelve el command que nosotros construimos incorporándole el manejo de errores:
    • +
    + +
    +
    +
    +      @Override
    +public void widgetSelected(SelectionEvent event) {
    +      try {
    +            this.action.execute();
    +      } catch (UserException exception) {
    +            this.context.getErrorViewer().showWarning(exception.getMessage());
    +      } catch (RuntimeException exception) {
    +            exception.printStackTrace();
    +            this.context.getErrorViewer().showError("Se produjo un error de sistema. Puede revisar el log de la aplicación para obtener más detalles");
    +      }
    +}
    +
    +    
    +
    +
    + +

    El bloque catch puede variar dependiendo de la versión de Arena que estén usando. Pero más allá de algunos detalles de implementación que pueden ver ustedes, lo importante es ver qué sucede con los dos tipos de excepción:

    + +
      +
    • errores de usuario/negocio: mostramos el error en una ventana de diálogo. ¿Qué dice el mensaje de error? A la ventana no le interesa, sabe que cualquier acción que disparemos puede dar este tipo de error, y que el mensaje contiene información importante para el usuario. Pero no acoplamos la UI al resto de los componentes del sistema: nos da lo mismo si el número de celular debe comenzar con 15, si ya existe otro alumno con el mismo legajo o si no podemos cargar una fecha de nacimiento futura para los empleados.
    • +
    • los errores de programa los catcheamos después, porque RuntimeException es más general que UserException. Hay una decisión de diseño de no envolver las excepciones chequeadas, para respetar así a quienes quieran trabajar con este tipo de excepciones.
    • +
    • mientras que la excepción de programa se “loguea” (haciendo un printStackTrace), las excepciones de negocio no tiene sentido registrarlas. Las excepciones de programa las leen los programadores, las de negocio le sirven al usuario para comprender que está tratando de usar el sistema de manera incorrecta, el mensaje de error le debe aportar una ayuda para solucionar este inconveniente y seguir adelante.
    • +
    • el log default hace un printStackTrace(), esto deja en el archivo standard output la pila de mensajes donde ocurrió el error. Este archivo puede ser voluminoso, entonces +
        +
      • se suele particionar los errores por aplicación (y a veces por módulo también)
      • +
      • también se registran datos adicionales, como usuario logueado, fecha y hora en que ocurrió el error, esto por lo general se puede parametrizar sin mucho esfuerzo
      • +
      • otra cosa que se suele hacer es activar/desactivar niveles de logueo para ver cómo está funcionando una aplicación (niveles debug/info/warning/error/fatal)
      • +
      • y el ErrorViewer sabe mostrar un mensaje de error al usuario (showError), en este caso mediante una ventana de diálogo
      • +
      +
    • +
    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/ui-web-intro-arquitectura.html b/wiki/articles/ui-web-intro-arquitectura.html new file mode 100644 index 0000000000..2bf228b0ad --- /dev/null +++ b/wiki/articles/ui-web-intro-arquitectura.html @@ -0,0 +1,604 @@ + + + + + + + + + + + Introducción a la Arquitectura web + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Introducción a la Arquitectura web +

    +
    + + + + + +
    +

    Arquitectura distribuida

    + +

    La arquitectura web trabaja con dos nodos:

    + +
      +
    • el cliente tiene un programa ejecutable (application client, el web browser o navegador es el más común)
    • +
    • y el servidor tiene otro programa ejecutable: en la materia será nuestro application server el que tendrá una VM donde vivan los objetos de negocio.
    • +
    + +

    Estos nodos son lógicos: pueden estar ubicados físicamente en la misma máquina, pero igualmente tendremos una separación de componentes en cliente y servidor.

    + +

    El cliente hace pedidos a través de un puerto contra el servidor, el servidor responde. El flujo de mensajes siempre comienza en el cliente:

    + +
      +
    • cliente pide servicio (request)
    • +
    • servidor responde (response)
    • +
    + +

    + image +

    + +

    Algunas consecuencias

    + +
      +
    • Nuestra aplicación pasa a ser una aplicación distribuida: va a tener una parte corriendo en el servidor y otra parte corriendo en el cliente. Dependiendo de la arquitectura que elijamos +
        +
      • podemos tener la mayor parte de la lógica en el servidor y tener un cliente liviano (thin) o ZAC (Zero Administration Client). Entonces lo que le llega al cliente es sólo un documento HTML, y es fácil mantener la aplicación cuando tengo muchos clientes ubicados
      • +
      • o bien podemos poner gran parte de la lógica en el cliente y utilizar la parte server solamente para sincronizar la información entre sesiones de usuario
      • +
      +
    • +
    • de todas maneras, por más liviano que sea el cliente, los browsers no son uniformes, entonces si queremos que una aplicación ande en todos ellos muchas veces vamos a tener que manejar código específico para cada plataforma (browser, versión, sistema operativo y a veces hasta el hardware).
    • +
    • como el cliente es el que dispara los pedidos, todas las interacciones entre el usuario y la aplicación deben ser iniciadas por el usuario, la aplicación no puede tomar la iniciativa. Ej: si tengo una lista de tareas pendientes, para que aparezca una nueva tarea hay que obligar al cliente a que dispare el refresh.
    • +
    + +

    Pedido/respuesta

    + +

    Antes de meternos más de lleno, nos preguntamos: la tecnología de objetos ¿es consistente con la metáfora “pedido-respuesta” (request/response)? Sí, en definitiva es la representación de lo que es un mensaje.

    + +

    Lo que pasa es que en un sistema con objetos no pongo restricciones: cualquiera puede ser emisor y cualquiera receptor. En cambio en la tecnología web siempre es el cliente el que pide y siempre el servidor el que responde.

    + +

    Cómo se implementa la comunicación

    + +

    El cliente dice: “necesito x”. Esto se traduce en una dirección de una página en particular, esa dirección recibe el nombre de URL (Uniforme Resource Locator, o forma de encontrar un recurso en el servidor):

    + +
    +  http://localhost:8080/html-css/index.html
    +
    +
    + +

    donde

    + +
      +
    • http es HyperText Transfer Protocol, el protocolo de comunicación por defecto que usan los navegadores +
        +
      • otros protocolos son https (donde los datos viajan encriptados), ftp, etc.
      • +
      +
    • +
    • localhost es el servidor web hacia el que vamos a conectarnos +
        +
      • en este caso localhost es el web server que está en la PC local, que equivale a la dirección IP 127.0.0.1
      • +
      • el servidor web puede ser una dirección IP o un nombre que luego es convertido a una dirección IP a través de un DNS (Domain Name Server)
      • +
      +
    • +
    • 8080 es el puerto donde el servidor está “escuchando” pedidos
    • +
    • y finalmente la página que queremos cargar, que recibe el nombre de recurso
    • +
    + +

    La forma en que publicaremos las páginas como rutas depende de la tecnología en la que trabajemos y lo veremos más adelante, lo importante es entender que una página html es accesible para un usuario con una ruta única llamada URL.

    + +

    HTTP

    + +

    Http es un protocolo no orientado a conexión que define la forma de comunicación entre el cliente y el servidor.

    + +

    Recordemos que no-orientado a conexión significa que no guarda ninguna información sobre conexiones anteriores, por lo que no tenemos el concepto de sesión de usuario, es un protocolo sin estado (stateless protocol). Esto tiene varias implicancias, la más fuerte es que requiere que la aplicación mantenga la información necesaria para mantener una sesión (por ejemplo, sabiendo qué usuario es el que está haciendo una operación).

    + +

    Un mensaje http tiene formato de texto, por lo que es legible al usuario y fácilmente depurable, como vemos en el siguiente video:

    + +

    + video +

    + +

    Abrimos en un navegador las herramientas de desarrollo (por lo general es la tecla F12), y en la solapa Network podemos inspeccionar las distintas respuestas que procesa el navegador, con el pedido http original que hace un mensaje de tipo GET.

    + +

    Tipos de mensaje

    + +

    Un cliente puede enviar un pedido al servidor utilizando diferentes métodos

    + +
      +
    • GET: asociada a una operación de lectura, sin ningún otro efecto
    • +
    • HEAD: es exactamente igual al pedido vía GET pero enviando únicamente el resultado de la operación en un header, sin el contenido o body
    • +
    • POST: se suele asociar a una operación que tiene efecto colateral, no repetible
    • +
    • PUT: está pensado para agregar información o modificar una entidad existente
    • +
    • DELETE: se asocia con la posibilidad de eliminar un recurso existente
    • +
    • OPTIONS: permite ver todos los métodos que soporta un determinado servidor web
    • +
    • TRACE: permite hacer el seguimiento y depuración de un mensaje http (se agrega información de debug)
    • +
    • CONNECT: equivalente a un ping, permite saber si se tiene acceso a un host
    • +
    + +

    Más adelante volveremos sobre esto al estudiar REST. Ahora veremos la diferencia entre hacer un pedido mediante GET vs. POST.

    + +

    Envío mediante GET method

    + +

    Aquí los parámetros viajan dentro de la URL como par clave=valor:

    + +
    +  http://www.appdomain.com/users?size=20&page=5
    +
    +
    + +
      +
    • ? delimita el primer parámetro
    • +
    • & delimita los siguientes parámetros
    • +
    + +

    La ventaja de utilizar este método es que dado que http es un protocolo no orientado a conexión, podemos reconstruir todo el estado que necesita la página a partir de sus parámetros (es fácil navegar hacia atrás o adelante). Por otra parte es el método sugerido para operaciones sin efecto, que recuperan datos de un recurso.

    + +

    Por otra parte, no es conveniente para pasar información sensible (como password o ciertos identificadores), algunos navegadores imponen un límite máximo de caracteres para estos pedidos y necesita codificar los caracteres especiales (p. ej. el espacio a %20) dado que el request solamente trabaja con el conjunto de caracteres ASCII.

    + +

    Envío mediante POST method

    + +

    Los parámetros viajan en el BODY del mensaje HTML, no se ven en la URL del browser. Aquí no hay restricciones de tamaño para pasaje de información y tampoco se visualizan los parámetros en la URL del browser.

    + +

    GET vs. POST

    + +

    La recomendación W3C (World Wide Web Consortium) dice que deberíamos usar

    + +
      +
    • GET cuando sepamos que se trata de consultas que no van a tener efecto colateral (no habrá modificación en el estado del sistema)
    • +
    • POST cuando sepamos que el procesamiento de la página causará una alteración del estado del sistema (al registrar el alquiler de una película, al modificar los datos de un socio o al eliminar un producto de la venta). Otros métodos posibles que veremos son PUT y PATCH, para modificaciones y alteraciones parciales, respectivamente.
    • +
    + +

    El camino de un pedido http

    + +
      +
    • el browser se conecta con el servidor a partir del dominio o IP (localhost = 127.0.0.1) y puerto
    • +
    • se envía la petición al servidor en base a dirección, método, parámetros, etc.
    • +
    • +

      el servidor responde a ese pedido: esa respuesta es una nueva página con un código de estado HTTP:

      + +
        +
      • 200 : OK
      • +
      • 401 : Unauthorized
      • +
      • 403 : Forbidden
      • +
      • 404 : Not Found
      • +
      • 405 : Method not allowed
      • +
      • 500 : Internal Server Error
      • +
      +
    • +
    + +

    El lector puede buscar la lista de códigos de error HTTP (las especificaciones RFC 2616 y RFC 4918) y formas de resolverlos.

    + +
      +
    • la aplicación cliente o user agent se desconecta del servidor una vez procesada la respuesta
    • +
    + +

    Consecuencias del mensaje http para las aplicaciones web

    + +

    La página es la mínima unidad de información entre cliente y servidor, lo que implica:

    + +
      +
    • problemas en la performance: no siempre debería refrescar toda la página si sólo necesito actualizar parcialmente la información de dicha página
    • +
    • problemas en el diseño: tengo dificultades para poder particionar una pantalla en componentes visuales
    • +
    • problemas de usabilidad: para que la página sea dinámica necesitamos forzar una comunicación con el servidor
    • +
    + +

    String oriented programming: la comunicación entre cliente y servidor involucra solo texto, necesitamos adaptar fechas, números, booleanos y también los objetos de negocio (socios de un videoclub, alumnos, materias, vehículos de una flota, etc.) así como las colecciones.

    + +

    Procesamiento de la respuesta en el cliente

    + +

    El servidor contesta con un string que tiene

    + +
      +
    • un header donde indica el resultado del pedido
    • +
    • un contenido, que forma parte del body, que puede ser HTML, json o cualquier otro formato que el cliente entienda
    • +
    + +

    + +

    + +


    +Arriba vemos la respuesta del navegador al buscar “Cuarteto de Nos” y abajo cómo procesa la consulta el cliente Postman. +

    + +

    + +

    + +

    Resumen

    + +
      +
    • Muchos clientes se conectan a un único servidor a través del protocolo HTTP
    • +
    • En el cliente corre un programa llamado user agent que es el encargado de establecer la comunicación con el web server. Se utiliza el concepto de thin client, es decir que se minimiza la lógica en los clientes, tendiendo a concentrarla en el servidor. Consecuencias: +
        +
      • se simplifica la utilización de la aplicación desde múltiples clientes sin costo de instalación ni mantenimiento.
      • +
      • se simplifica la lógica al mantener toda la aplicación centralizada.
      • +
      +
    • +
    • La descripción de las pantallas se basa en HTML. Es decir, una página dinámica es un programa que genera un String conteniendo código HTML.
    • +
    • Progresivamente se ha incrementado la tendencia a describir las cuestiones estéticas utilizando CSS, por lo tanto la descripción de una vista estará dada por una combinación de HTML y CSS.
    • +
    • La comunicación entre el cliente y el servidor está dada en la forma de pedido-respuesta (request-response).
    • +
    • Todas las interacciones entre el usuario y la aplicación deben ser iniciadas por el usuario, la aplicación no puede tomar la iniciativa.
    • +
    • La respuesta para cada pedido es una página nueva, la mínima unidad de comunicación entre el cliente y el servidor es una página. Esto tiene consecuencias tanto de performance como de usabilidad y también de diseño. Existen muchos tipos de pedido pero los más usuales son GET y POST. Los dos puntos anteriores limitan gravemente la posibilidad de utilizar mecanismos de binding.
    • +
    • Cada pedido es independiente de los anteriores, es decir, la tecnología no provee de un soporte directo para manejar el estado de la conversación entre ambos procesos (stateless). Para modelar procesos que requieran de una comunicación más poderosa que esa deberán proveerse herramientas adicionales, frecuentemente manipuladas ad-hoc.
    • +
    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/unexpected-----.html b/wiki/articles/unexpected-----.html new file mode 100644 index 0000000000..0f86b9b2ae --- /dev/null +++ b/wiki/articles/unexpected-----.html @@ -0,0 +1,360 @@ + + + + + + + + + + + unexpected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + unexpected +

    +
    + + + +
    +

    Un error que puede aparecer al programar en haskell es:

    + +
    ERROR [file:.\tp1](file:.\tp1) funcional:- Syntax error in expression (unexpected
    + ;', possibly due to bad layout)
    +
    + +

    ¡Pero yo no puse ningún punto y coma! ¿Qué onda?

    + +

    La respuesta corta es que hay que revisar la sintaxis y en particular la indentación. El por qué de ese mensaje tan raro, a continuación.

    + +

    Indentación

    + +

    El haskell usa una sintaxis “bidimensional” (no se asusten), eso quiere decir que si vos “indentás” algo, eso tiene un significado. Entonces antes de continuar hay que entender el concepto de indentación. Indentar algo es dejar espacios o tabs adelante del código, generalmente uno lo hace para que se lea mejor, por ejemplo

    + +
    function fact(n: integer): longint; begin
    +
    +   if (n = 0) then
    +       fact := 1
    +   else
    +       fact := n * fact(n - 1);
    +
    +end;
    +
    + +

    Podemos ver que el programador dejó algunos espacios antes de las palabras if y then, entonces visualmente es claro que todo eso queda dentro del bloque definido por begin/end. De la misma manera las líneas de código que están dentro del if y del else tienen aún más espacios (“más indentación”).

    + +

    Sintaxis “bidimensional”

    + +

    Como dijimos, el haskell utiliza una sintaxis bidimensional, es decir, en pascal o c la indentación son opcionales, no tienen significado, es decir, uno los pone sólo para entender mejor el programa; en cambio en haskell no hacen falta los / de pascal ni las llaves de C para demarcar un bloque de código. En haskell un bloque es demarcado directamente con la indentación.

    + +

    Entonces la función que en C se escribiría:

    + +
    int suma(int a, int b)
    +{
    +   return a + b;
    +}
    +
    + +

    En haskell no necesita de las llaves, porque se da cuenta a partir de la indentación:

    + +
    suma a b =
    +   a + b
    +
    + +

    Tampoco son necesarios los tipos ni el return, pero eso es otro tema, lo que nos interesa acá es que no son necesarias las llaves ni el punto y coma, porque con la indentación y el fin de línea es suficiente para que el compilador entienda dónde empieza y termina la función. (En este caso sería aún más simple poner todo en una sola línea, pero algunas funciones complejas tienen más de una línea.)

    + +

    En resumen, si vos indentás mal es análogo a olvidarse una llave o un o un ‘;’ en otro lenguaje.

    + +

    ¿Por qué entonces dice unexpected ‘;’, si yo no puse ningún ‘;’?

    + +

    Se puede entender como que el haskell a partir de la sintaxis bidimensional “completa” los demarcadores de comando y de bloque, de una forma similar al C, quedando algo parecido a:

    + +
    suma a b = {
    +   a + b;
    +}
    +
    + +

    De hecho, es posible escribir la función de esa manera si uno prefiere… pasa que obviamente uno prefiere la sintaxis con menos chirimbolos.

    + +

    Entonces, cuando dice “unexpected ‘;’” lo más probable es que no está entendiendo el “layout” que ustedes le dieron a al función, es decir, la forma en que la indentaron. Ese “bad layout” hace que en su traducción aparezca un “;” en algún lado que no tiene sentido. Saber dónde está ese “;” no es sencillo, hay que revisar el layout de la función.

    + +

    Ejemplo de problemas de indentación en Haskell

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/unificacion-y-pattern-matching.html b/wiki/articles/unificacion-y-pattern-matching.html new file mode 100644 index 0000000000..cbab5545d0 --- /dev/null +++ b/wiki/articles/unificacion-y-pattern-matching.html @@ -0,0 +1,509 @@ + + + + + + + + + + + Unificacion y pattern matching + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Unificacion y pattern matching +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Unificación

    + +

    Dentro de los conceptos del paradigma lógico no está incluido el concepto de asignación. Para dejar en claro esto vamos a llamar a esta idea Asignación Destructiva, esto se debe a que una asignación me permite “destruir” el valor que tiene una variable en un momento dado y reemplazarlo por otro. Esta idea de asignación no tiene sentido cuando pensamos en incógnitas (si en un momento dado decimos que una variable X vale 1, su valor será 1 y ningún otro hasta que se empiece a buscar otra solución a la misma consulta, en ese momento se desligan todas las variables y se empieza de nuevo). Las variables en el paradigma lógico se asemejan a la idea de variable matemática, y el mecanismo por el cual se le dan valores a las variables se llama unificación. Cuando una variable que no tiene ningún valor pasa a tenerlo vamos a decir que dicha variable a sido ligada, en caso contrario la variable se encuentra sin ligar o no ligada.

    + +

    Si nuestra base de conocimiento es

    + +
    +
    +
    +      padre(homero,bart).
    +
    +padre(homero,maggie).
    +
    +padre(homero,lisa).</code>
    +
    +Y hago la consulta
    +
    +?- padre(X,lisa). X = homero
    +
    +    
    +
    +
    + +

    Cómo obtuvo ese resultado Prolog?

    + +

    Básicamente lo que hace Prolog es buscar un consecuente (revisar al principio de todo qué era eso de consecuente) dentro de todas las cláusulas de nuestra base de conocimiento que unifique con la consulta. Podemos ver un poco la unificación o falta de unificación entre dos hechos (que serían la consulta y el consecuente) haciendo consultas en SWI que jueguen con el = (igual), para la consulta de recién tenemos:

    + +

    El consecuente de la primer cláusula NO unifica con la consulta

    + +
    +
    +
    +      ?- padre(X,lisa) = padre(homero,bart).
    +
    +No
    +
    + %El consecuente de la segunda cláusula **NO** unifica con la consulta
    +
    +?- padre(X,lisa) = padre(homero,maggie).
    +
    +No
    +
    + %El consecuente de la tercer cláusula **unifica** con la consulta
    +
    +?- padre(X,lisa) = padre(homero,lisa).
    +
    +X = homero
    +
    +    
    +
    +
    + +

    OJO el = (igual) nooooo lo vamos a usar en los programas, lo usamos acá solamente porque nos ayuda a estudiar sobre la unificación.

    + +

    Este ejemplo es fácil ya que todas las cláusulas son hechos pero no es nuestra intención entender en profundidad el mecanismo de unificación. Si se tratara de reglas, tiene que pasar que se resuelvan los antecedentes de la cláusula cuyo consecuente unificó con la consulta; en el proceso se agotan todas las posibles soluciones.

    + +

    Entonces, se dice que 2 términos unifican si existe algún reemplazo de todas las variables (de los 2 términos) que haga a los términos iguales; se dice que una consulta matchea con un consecuente si el predicado es el mismo y hay un reemplazo coherente que hace que todos los argumentos unifiquen. P.ej. con el reemplazo X/homero pasa que X queda igual que homero (primer argumento) y también que lisa es igual que lisa (segundo argumento), entonces la consulta padre(X,lisa) unifica con padre(homero,lisa) mediante el reemplazo X/homero.

    + +

    Nos alcanza pensar que un término es un individuo (simple o compuesto - estos últimos pueden tener variables) o una consulta (como en el primer ejemplo).

    + +
    +
    +
    +      %Dos individuos iguales unifican ?- 1 = 1.
    +Yes
    +
    +?- homero = homero.
    +Yes
    +
    +?- fecha(1,1,1901) = fecha(1,1,1901).
    +Yes
    +
    +?- [a,b,c] = [a,b,c].
    +Yes
    +
    +%Existen reemplazos de variables que hagan los términos iguales por lo tanto unifican ?- X = homero.
    +X = homero.
    +
    +?- F = fecha(1,1,1901).
    +F = fecha(1,1,1901).
    +
    +?- fecha(D,1,A) = fecha(1,M,1901).
    +D= 1
    +M= 1
    +A = 1901
    +
    +%Dos individuos distintos no unifican ?- 1 = 2.
    +No
    +
    +?- homero = marge.
    +No
    +
    +?- fecha(1,1,1901) = fecha(1,1,2010).
    +No
    +
    +?- [a,b,c] = [c,b,a].
    +No
    +
    +%No existen reemplazos de variables que hagan los términos iguales por lo tanto no unifican ?- fecha(D,1,2010) = fecha(1,M,1901). No ?- [1,2,X] = [2,2,3].
    +No
    +
    +?- [1,2,3] = [X,X,3].
    +No
    +
    +    
    +
    +
    + +

    Y pattern-matching?

    + +

    Bueno, la diferencia entre decir pattern matching y unificación es bastante gris (algunos autores lo consideran sinónimos). Es muy común decir “unifica” o “matchea” indistintamente.

    + +

    Vamos a hablar de unificación de variables en relación al valor que las mismas toman en base a una consulta y de pattern matching cuando en el encabezado del predicado se determina la forma que tiene que tener

    + +

    Mayormente vamos a hablar de pattern matching al involucrar individuos compuestos, ya que a partir de los mismos se pueden definir patrones complejos con los cuales los valores usados en las consultas deberían coincidir.

    + +

    Los patrones más básicos que podemos encontrar son los que no limitan en absoluto qué valores pueden matchear (las variables) y los que sólo matchean si son exactamente iguales (valores concretos). Por ejemplo, una solución de factorial podría resolverse usando pattern matching de modo que existen dos definiciones: una que sólo es válida para el factorial de 0 y otra que es válida para cualquier número.

    + +
    +
    +
    +      factorial(0, 1).
    +factorial(N, F) :- N > 0,
    +  M is N - 1,
    +  factorial(M, FM),
    +  F is N * FM.
    +
    +    
    +
    +
    + +

    Si hacemos las siguientes consultas:

    + +
    +
    +
    +      ?- factorial(2, Factorial).
    +
    +    
    +
    +
    + +

    El 2 no matchea con el 0, pero sí con la variable N, por ende sólo la segunda cláusula es considerada para responder a la consulta.

    + +
    +
    +
    +      ?- factorial(0, Factorial).
    +
    +    
    +
    +
    + +

    El 0 matchea con el 0 y también con la variable N, por ende ambas cláusulas son usadas para responder. Sin embargo, si la variable N se unificó con el valor 0, la consulta N > 0 da falso y no continúa ejecutando porque ya falló.

    + +

    Al trabajar con individuos compuestos podemos usar otro tipo de patrones que restrinjan parcialmente qué valores pueden pueden matchear.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/uso-de-features-de-lenguajes-dinamicos.html b/wiki/articles/uso-de-features-de-lenguajes-dinamicos.html new file mode 100644 index 0000000000..26ec0cb91b --- /dev/null +++ b/wiki/articles/uso-de-features-de-lenguajes-dinamicos.html @@ -0,0 +1,387 @@ + + + + + + + + + + + Uso de features de lenguajes dinamicos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Uso de features de lenguajes dinamicos +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Terminología

    + +

    El término “lenguaje dinámico” es usado en la industria con poca rigurosidad. En lugar de intentar de dar una definición precisa, señalaremos dos características típicas de estos lenguajes (aunque bien se podrían incluir muchas más):

    + + + +

    Es interesante marcar que la primera característica no es suficiente para hacer dinámico al lenguaje: si pudieramos reemplazar el sistema de verificación de tipos de Java para que fuera realizado enteramente en tiempo de ejecución, pero mantuviéramos su modelo de objetos y API de metaprogramación tal como la conocemos, seguiría siendo un lenguaje “estático”: el tipado dinámico no es condición suficiente.

    + +

    Por otro lado, el tipado dinámico no es en teoría una condición necesaria para la metaprogramación, pero sí lo simplifica notablemente: la auto-modificación en lenguajes con tipado estático requeriría de sistemas de tipos mucho más complejos que los que estamos acostumbrados a ver en la mayoría de los lenguajes.

    + +

    Features destacados

    + +

    A continuación mencionamos algunos features destacados por su utilidad para metaprogramar y hacer DSLs.

    + +
      +
    • Envío de mensajes “dinámicos”: mandar un mensaje a un objeto a partir de su nombre
    • +
    • Interceptores de código: Los lenguajes dinámicos presentan interesantes capacidades de intercepción de código, ya que ofrecen puntos en los cuales uno puede “colgarse” del mecanismo de resolución de métodos (method lookup). El más simple y usado de ellos es method missing o does not understand: se evaluará este método siempre que se le envie un mensaje a un objeto que este no entienda. En Groovy también existe el análogo para los accessors (propertyMissing).
    • +
    • Clases abiertas (open classes): Que una clase sea abierta significa que puede ser modificada luego de ser definida, para agregar, quitar o modificar cualquier aspecto de la misma (métodos, atributos, jerarquía de herencia…)
    • +
    • Autoclases (Eigen Class): una clase exclusiva de esa instancia y que no se comparte con las demás permitiendo modificar la estructura y comportamiento de una instancia específica en vez de todas las de una determinada clase.
    • +
    • Sintaxis flexible: Algunos lenguajes como Ruby permiten jugar con la sintaxis de modo que se pueda incrementar la expresividad del código. Algunos ejemplos de esto podría ser: +
        +
      • omitir paréntesis y puntos en el envío de mensajes
      • +
      • redefinición de operadores
      • +
      • contextualizar bloques de código de modo que se pueda elegir un receptor implícito de los mensajes
      • +
      +
    • +
    + +

    Para profundizar y ver algunos ejemplos

    + + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/value-object.html b/wiki/articles/value-object.html new file mode 100644 index 0000000000..9c18c73b2b --- /dev/null +++ b/wiki/articles/value-object.html @@ -0,0 +1,435 @@ + + + + + + + + + + + Value object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Value object +

    +
    + + + +
    +

    Introducción

    + +

    + La definición de Value Object varía bastante de autor en autor. Algunas visiones diferentes sobre este concepto están plasmadas aquí. +

    + +

    Entendemos como Value Object a aquellos objetos que tienen una semántica de valor (en contraposición con semántica de referencia), es decir cuya identidad no es importante. Dos value objects ser intercambiables, esperando iguales resultados, en tanto ambas instancias exhiban el mismo comportamiento desde el punto de vista del observador. Dicho de otra forma, son objetos para los que podría eventualmente tener una copia del mismo, y daría lo mismo enviarle un mensaje al original o su copia.

    + +

    Una consecuencia importante de que los Value Object no tengan identidad importante, es que no tienen estado visiblemente mutable.

    + +

    Los Value Object pueden ser también analizados como un patrón de diseño. Se recomienda el capitulo correspondiente en este libro

    + +

    Los Value Objects pueden tener un estado visible inmutable (por ejemplo, para modelar una fecha), aunque también puede darse el caso en que tal estado no exista (por ejemplo, para modelar la función identidad) o se encuentre comletamente encapsulado (por ejemplo, una función aplicada parcialmente encapsula complementanete el estado de las variables que que fueron encerradas en su contexto)

    + +

    Los Value Objet aún puede tener un estado mutable interno, en tanto este no sea expuesto a través de su interfaz, lo que habilita a que presenten evaluación diferida en en sus variables de instancia.

    + +

    Impacto en el diseño

    + +

    Implementación

    + +

    Consideraciones sobre el subtipado y las relaciones de equivalencia

    + +

    En Java

    + +
    +
    +
    +      public class Final {
    +  
    +  private final String folio;
    +  private final Integer libro;
    +  private final Integer nota;
    +  private final Alumno alumno;
    +  
    +  public Final(String folio, String libro, Integer nota, Alumno alumno) {
    +    this.libro = libro;
    +    this.folio = folio;
    +    this.nota = nota;
    +    this.alumno = alumno;
    +  }
    +  public boolean estaAprobado() {
    +    return nota >= 4;
    +  }
    +  public Alumno getAlumno() {
    +    return alumno;
    +  }
    +
    +  //demas getters
    +}
    +
    +    
    +
    +
    + +

    Nótese que el estado, de existir, de un ValueObject no tiene porqué estar conformado exclusivamente por tipos primitivos (primitive obsession).

    + +

    Tampoco tiene porqué estar desprovisto de comportamiento (dto/anemic object), de hecho, normalmente lo tiene y es función de su estado.

    + +

    Un ValueObject puede exponer su estado interno, como también puede encapsularlo completamente (ej [Function Object])

    + +

    Scala

    + +
    +
    +
    +      class Final(val folio:String, val libro:Int, val nota:Int, val alumno:Alumno ) {
    +  def estaAprobado = nota >= 4
    +}
    +
    +case class Final(val folio:String, val libro:Int, val nota:Int, val alumno:Alumno) {
    +  def estaAprobado = nota >= 4
    +}
    +
    +    
    +
    +
    + +

    En lenguajes con tipado dinámico

    + +

    en C (como un TAD)

    + +

    Si bien en C no tenemos objetos, podemos también implementar TADs con semántica de valor.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/variables-locales-en-metodos.html b/wiki/articles/variables-locales-en-metodos.html new file mode 100644 index 0000000000..4513bb000d --- /dev/null +++ b/wiki/articles/variables-locales-en-metodos.html @@ -0,0 +1,348 @@ + + + + + + + + + + + Variables locales en metodos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Variables locales en metodos +

    +
    + + + +
    +

    Se pueden usar variables locales a los métodos, lo cual puede ayudar la legibilidad o para evitar repetir la evaluación de una misma consulta a lo largo del método. Son análogas a las variables locales de procedimientos que deberían conocer de Algoritmos.

    + +

    Cómo se definen y usan: ahí va un ejemplo rápido (no importa mucho lo que hace)

    + +
     miMetodoLoco: unNumero
    +   **| varLocal1 varLocal2 varLocal3 |**
    +   varLocal1 := 4.
    +   varLocal2 := varLocal1 + 5.
    +   varLocal3 := varLocal1 / unNumero.
    +   ^ (varLocal1 max: varLocal2) min: varLocal3.
    +
    + + + + + + + + +
    En este método se definen tres variables locales entre pipes (). Las primeras tres líneas luego de esta declaración asignan las tres variables (o sea, hacen que referencien a un objeto). Luego puedo mandarle mensajes a los objetos referenciados por esas variables y usar esas referencias tantas veces como quiera.
    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/variables-y-metodos-de-clase.html b/wiki/articles/variables-y-metodos-de-clase.html new file mode 100644 index 0000000000..fe44976bc9 --- /dev/null +++ b/wiki/articles/variables-y-metodos-de-clase.html @@ -0,0 +1,535 @@ + + + + + + + + + + + Variables y metodos de clase + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Variables y metodos de clase +

    +
    + + + +
    +

    Mensajes y Métodos de clase

    + +

    Las clases son objetos, y como todos los objetos pueden tener atributos y ademas les podemos mandar mensajes. Pero las clases son objetos con responsabilidades especiales, la más común es la de crear nuevos objetos. Cada vez que a le mando el mensaje new a una clase obtengo una nueva instancia de esa clase. Podemos crear nuevas instancias en cualquier momento de nuestro programa (en el workspace, dentro de un método, etc).

    + +

    Entonces, los mensajes de clase son mensajes que entienden las clases, no las instancias de las mismas. El nombre (selector) de un mensaje de clase se escribe igual que siempre (empieza con minúscula).

    + +

    Algunos ejemplos:

    + +

    Workspace:

    + +
    +
    +
    +        pepita:= Golondrina new.
    +
    +    
    +
    +
    + +

    new es uno de los primeros mensajes de clase que aprendemos: nos devuelve una nueva instancia de la clase que recibe el mensaje. En este caso, devuelve una golondrina.

    + +

    Workspace:

    + +
    +
    +
    +        hoy := Date today.
    +
    +    
    +
    +
    + +

    today es un mensaje de clase que le mando a la clase Date y me devuelve un objeto que representa la fecha de hoy.

    + +

    Workspace:

    + +
    +
    +
    +        items:= Bag with: 'brujula' with: 'botellaDeGrogXD' with: 'catalejo'.
    +
    +    
    +
    +
    + +

    with:with:with: es un mensaje que entienden las clases de colecciones (en este caso Bag es la clase que recibe el mensaje). with:with:with: devuelve una nueva colección, que tiene los tres elementos adentro. En éste caso, devuelve un bag con la brújula, la botella y el catalejo.

    + +

    En general es deseable tener una forma de crear objetos que ya estén inicializados adecuadamente para poder usarlos inmediatamente, y no que arranquen en un estado inválido y requieran ser configurados a posteriori.

    + +

    ¿Cómo escribo métodos de clase?

    + +

    Cada mensaje de clase debe tener asociado un método de clase (su codificación).

    + +
      +
    • En Pharo: En el segundo panel del System Browser, apretando el boton class, escriben el método como hasta ahora. (No se olviden de volver a apretar instance para escribir metodos de instancia)
    • +
    • En el parcial: simplemente pongan (MC) al lado del método, para diferenciarlo de los métodos de instancia.
    • +
    + +

    Workspace:

    + +

      barbanegra := Pirata nuevoConItems: items ebriedad: 100 monedas: 1500.

    + +

    El mensaje nuevoConItems:ebriedad:monedas: se lo mando a la clase Pirata y me devuelve un nuevo pirata ya inicializado con los items, la ebriedad y las monedas que le indiquemos.

    + +

    Codificación:

    + +
    +
    +
    +       #Pirata
    + (MC)  >> nuevoConItems: losItems ebriedad: nivelEbriedad monedas: unasMonedas
    +    |unPirata|
    +  unPirata:= self new.
    +  unPirata items: losItems.
    +  unPirata ebriedad: nivelEbriedad.
    +  unPirata monedas: unasMonedas.
    +  ^unPirata.
    +
    +    
    +
    +
    + +

    Recordemos que, como el que recibe este mensaje es una clase, acá self es la clase, no una instancia. El motivo por el cual es importante usar self en vez de escribir el nombre de la clase (en este caso Pirata) es porque estos métodos también se heredan, y si subclaseamos Pirata no se va a comportar como queremos cuando le mandemos nuevoConItems:ebriedad:monedas: a la subclase. Al usar self indicamos que el mensaje debe enviarse al objeto que recibió nuevoConItems:ebriedad:monedas:, o sea que si se lo mandamos a una subclase de Pirata, la instancia creada será de dicha clase.

    + +

    ¿Que son las variables de clase? ¿Para que sirven?

    + +

    Las variables de clase nos sirven cuando queremos que nuestros objetos tengan alguna referencia a algún valor, que sea el mismo para todas las instancias de esa clase, y que ademas pueda cambiar (por eso usamos una variable y no hardcodeamos ese valor en el código del programa, asumiendo que es posible).

    + +

    Si usáramos una variable de instancia con la intención de settear el mismo valor a todas las instancias de esa clase, y luego queremos cambiar el valor de modo de afectar a todas las instancias, tengo que poder encontrar todas las instancias ya existentes para poder mandarles el mensaje para que actualicen su referencia… Y si tengo muchos muchos objetos eso no esta bueno, no sólo por la complejidad innecesaria del problema, sino también porque la performance puede verse afectada. Este problema desaparece si tengo un único objeto que conozca este valor que quiero que varios objetos conozcan, y como todo objeto conoce la clase a la que pertenece, podemos dejar que sea responsabilidad de la clase recordar y manipular este estado, y que sus instancias usen ese valor cuando lo necesiten.

    + +

    Si tengo una variable de clase y cambio el valor al que referencia, automáticamente todas las instancias que yo cree a partir de esa clase en la vida van a conocer ese nuevo valor, porque lo conoce su clase y ellas conocen a su clase :)

    + +

    Diferencia con las variables de instancia

    + +

    Las variables de instancia son propias de cada objeto, si cambio una referencia en un objeto la referencia de otro de la misma clase no cambia (aunque las variables se llamen igual). Si cambio la referencia de una variable de clase, todas las instancias van a verse afectadas, ya que no es una referencia propia.

    + +

    En Smalltalk, para declarar una variable de instancia (por ejemplo, dada una clase Pirata, para decir que cada pirata conoce cuántas monedas tiene) debíamos indicarlo de esta forma:

    + +
    +
    +
    +      Object subclass: #Pirata
    +   instanceVariableNames: 'monedas'
    +   classVariableNames: ''
    +   category: 'Yaaaar'
    +
    +    
    +
    +
    + +

    Para declarar una variable de clase en cambio, el nombre de la variable debe ir entre las comillas que siguen a classVariableNames:, por convención inician con mayúscula. Suponiendo que el dinero máximo que tiene que tener un pirata para poder saquear un objetivo es igual para todas las misiones de saqueo es el mismo, podemos ponerlo en una variable de clase

    + +
    +
    +
    +      Object subclass: #Saqueo
    +   instanceVariableNames: ''
    +   classVariableNames: 'DineroMaximo'
    +   category: 'Yaaaar'
    +
    +    
    +
    +
    + +

    ¿Como las usamos?

    + +

    Dentro de un método de instancia de Saqueo podemos directamente usar una variable de clase definida para la clase Saqueo, por ejemplo:

    + +
    +
    +
    +       #Saqueo
    +   >>esUtil: unPirata
    +     ^(unPirata dineroDisponible < **DineroMaximo**) and: [ unPirata teAnimasASaquear: objetivo].
    +
    +    
    +
    +
    + +

    Pero, como el DineroMaximo es algo que en realidad “está guardado” en la clase, (y por lo tanto es responsabilidad de la clase conocerlo), otra alternativa es mandarle un mensaje a la clase:

    + +
    +
    +
    +       #Saqueo
    +   >>esUtil: unPirata
    +     ^(unPirata dineroDisponible < **Saqueo** dineroMaximo) and: [ unPirata teAnimasASaquear: objetivo].
    + **(MC)>> dineroMaximo**
    +      **^DineroMaximo**
    +
    +    
    +
    +
    + +

    Por último, una forma más correcta sería poniendo self class, de esta manera:

    + +
    +
    +
    +       #Saqueo
    +   >>esUtil: unPirata
    +     ^(unPirata dineroDisponible < **self class** dineroMaximo) and: [ unPirata teAnimasASaquear: objetivo].
    + (MC)>> dineroMaximo
    +      ^DineroMaximo
    +
    +    
    +
    +
    + +

    La razón por la que es más correcta, tiene que ver con la existencia de Herencia como se mencionó anteriormente. Así damos la posibilidad a una subclase a redefinir dineroMaximo.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/variables.html b/wiki/articles/variables.html new file mode 100644 index 0000000000..552cb41510 --- /dev/null +++ b/wiki/articles/variables.html @@ -0,0 +1,522 @@ + + + + + + + + + + + Variables + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Variables +

    +
    + + + +
    +
    + + + + + + +
    +
    +

    Contents

    +
    + +
    +

    Referencias

    + +

    En objetos una variable es una referencia a un objeto. La mayoría de las referencias pueden ser reapuntadas a otros objetos mediante la operación de asignación. Al hacerlo eso no modifica al objeto previamente referenciado.

    + +

    Hay distintos tipos de referencias, dependiendo del contexto en el cual son declaradas:

    + +
      +
    • atributos: se usan para que el objeto mantenga un estado propio.
    • +
    • locales: se declaran dentro de un método, sólo son visibles desde el mismo, y no sobreviven a su ejecución.
    • +
    • parámetros: forman parte de la firma del método, no pueden ser reapuntadas a otros objetos dentro del método.
    • +
    + +

    Asignación de variables

    + +

    La asignación de variables se logra de la siguiente forma:

    + +
    +
    +
    +      variable = expresion-que-devuelve-un-objeto
    +
    +    
    +
    +
    + +

    y debe interpretarse que cuando se evalúa esta línea, la variable referencia al objeto resultado de la expresión de la derecha.

    + +

    Entonces, al asignar una variable no estoy creando ningún objeto ni estoy cambiando al objeto referenciado anteriormente por dicha variable, sólo se cambia cuál es el objeto al que está apuntando esa referencia.

    + +

    var y const

    +

    En Wollok, las referencias pueden declararse como variables (con la palabra reservada var) o como constantes (con la palabra reservada const). Las constantes están pensadas para ser usadas siempre que no se espere que la referencia pueda cambiar de valor, con lo cual intentar asignar una constante luego de su inicialización no está permitido.

    + +
    +
    +
    +      var edad = 15
    +const iva = 21
    +edad = 16 // esto anda perfecto
    +iva = 19 // esto tira error en tiempo de compilación
    +
    +    
    +
    +
    + +

    Error común: ¿qué significa “cambiar un objeto”?

    +
      +
    • ¿Lo cambio por otro?
    • +
    • ¿O le cambio sus atributos?
    • +
    + +

    Miremos el siguiente ejemplo:

    +
    +
    +
    +      const laPreferida = pepita // atentos al const
    +laPreferida.volar() // ¿Qué sucede en este caso? ¿Da error? 
    +laPreferida = pepona // ¿Y en este caso?
    +
    +    
    +
    +
    + +

    laPreferida.volar() no da error. Esto es porque al enviar el mensaje volar(), laPreferida (que apunta al mismo objeto que pepita) está cambiando su estado interno, su energía. ¡Pero la flecha laPreferida no se modifica! Se modifica sólo la energía de pepita al volar.

    + +

    En cambio, en laPreferida = pepona sí hay un error de compilación. Estoy intentando modificar a dónde apunta laPreferida, pero como esa referencia es const nunca podrá dejar de apuntar a pepita.

    + +

    Es importante entender que const laPreferida no significa que el objeto no pueda modificar su estado interno, sino que no puedo hacer que la flecha laPreferida apunte a otro objeto.

    + +

    Inicialización

    + +

    Un problema común que suele darse con atributos de los objetos es olvidarse de inicializarlos.

    + +

    Lo que sucede cuando una variable no ha sido inicializada puede variar de un lenguaje a otro: algunos (por ejemplo Smalltalk) tienen un objeto especial para representar la nada que entienden muy poquitos mensajes, otros (como Java o Wollok) directamente usan un valor primitivo. Pero lo importante es que para poder usar una variable de forma razonable, la misma debería referenciar a un objeto que entienda los mensajes que esperamos mandarle, de lo contrario se generará un error.

    + +

    ¿Cuál es el momento adecuado para inicializar un atributo? Si bien podrían darse situaciones en las cuales se quiera o necesite postergar la inicialización de un atributo, lo más común es querer inicializar los atributos al momento de la creación del objeto, de esa forma nunca se llegará a un estado en el cual el se le mande un mensaje al objeto y el mismo falle porque no se haya inicializado un atributo previamente.

    + +

    En Wollok podemos inicializar las variables al momento de declararlas. Eso en general es suficiente para trabajar con objetos bien conocidos (como en el ejemplo que se muestra más adelante). En caso de trabajar con objetos instanciados a partir de clases, es posible inicializar los atributos con valores distintos para cada instancia usando las herramientas de instanciación disponibles (en otros lenguajes en los cuales las clases son objetos, como Smalltalk, esto se logra mediante mensajes a las clases).

    + +

    Ejemplo completo

    + +

    Dado el siguiente código Wollok:

    + +
    +
    +
    +      object pepita {
    +  var energia = 100
    +  
    +  method energia(cantidad) {
    +    energia = cantidad
    +  }
    +}
    +
    +    
    +
    +
    + +

    … y luego le mando el mensaje…

    + +
    +
    +
    +      pepita.energia(50)
    +
    +    
    +
    +
    + +

    Cuando el objeto se crea, la variable energía se inicializa apuntando al objeto 100. Al mandar el mensaje para settearle la energía, el atributo energia que tiene pepita pasa de apuntar a 100 a apuntar a 50. O sea que sólo cambia a quién conoce pepita mediante la referencia energia.

    + +

    SIEMPRE lo que se encuentre a la izquierda de la asignación debe ser una variable, no se puede asignar un objeto (y por el mismo motivo no se puede asignar un envío de mensajes). Las siguientes expresiones son inválidas:

    + +
    +
    +
    +      3 = 5                 // <--- 3 es un objeto, no una referencia!!!
    +pepita.energia() = 10 // <--- pepita.energia() es un envío de mensajes, no una referencia!!!
    +
    +    
    +
    +
    + +

    En ningún caso vamos a poder modificar desde fuera del objeto que tiene una referencia el valor de la misma, siempre hay que mandarle un mensaje a ese objeto para que la cambie. Esto está relacionado con la idea de encapsulamiento, que es una de las bases del paradigma de objetos.

    + +

    Atributos: errores comunes

    + +

    Los atributos son obviamente muy útiles, ya que permiten que un objeto recuerde toda la información que necesita para poder usarla en cualquier momento. Sin embargo, hay que ser criteriosos respecto a cuándo usarlos, ya que pueden ser el motivo de inconsistencias y dificultad para mantener nuestros programas.

    + +

    Los siguientes son los algunos errores comunes de ver respecto al uso de atributos:

    + +
      +
    • Atributos redundantes: si cierta pieza de información puede ser calculada a partir de otra, no uses un atributo que tenga que ser mantenido consistente, usá un método que calcule lo que necesitás a partir de la otra información disponible. Para más información podés leer este artículo
    • +
    • Atributos innecesarios: no hay que perder de vista que nuestro programa es un modelo, y por ende no hace falta que el objeto recuerde información que luego no va a ser usada.
    • +
    • Uso de atributos en vez de locales: si necesitamos recordar cierta información sólo dentro de la ejecución de un método, lo correcto es usar una local, no un atributo.
    • +
    + +

    Como regla general para evitar estos problemas, preguntate: ¿hay alguna forma de no usar un atributo para lo que estás haciendo? si la hay, no uses un atributo.

    + +

    ¿Y las referencias circulares? Es perfectamente válido que dos objetos se conozcan entre ellos, en el caso de que sea necesario obviamente, las reglas anteriores valen también para esto. El único recaudo que hay que tener es asegurar la consistencia del estado de ambos objetos, lo cual puede simplificarse asegurando que esas referencias se modifiquen dentro de una misma operación, y no de forma independiente.

    + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/warning--singleton-variables.html b/wiki/articles/warning--singleton-variables.html new file mode 100644 index 0000000000..bd5041008f --- /dev/null +++ b/wiki/articles/warning--singleton-variables.html @@ -0,0 +1,343 @@ + + + + + + + + + + + Warning singleton variables + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Warning singleton variables +

    +
    + + + +
    +

    Las singleton variables son variables que vos escribiste en tu predicado pero no se usan. Por ejemplo:

    + +

    “Soy feliz si tengo algun amigo”

    + +
    esFeliz(Alguien) :- amigoDe(Alguien,**UnAmigo**).
    +
    + +

    Ahí la variable UnAmigo no la usás en otro lado, por lo que te dice que es Singleton. Como a vos no te interesa “usar” a ese UnAmigo (Sólo te interesa saber si existe, no quién es), podés poner una variable anónima:

    + +
    esFeliz(Alguien) :- amigoDe(Alguien,**_**).
    +
    + +

    Y así ya no te chilla.

    + +

    Ojo, a veces pasa que escribís mal una variable, entonces te dice “eh, singleton, ésta no la estás usando en otro lado” Por ejemplo:

    + +
    esFeliz(**Alguin**) :- amigoDe(**Alguien**,_).
    +
    + +

    Y ahí sólo tenés que arreglar tu error de tipeo.

    + +

    En resumen, si tenés un Warning,

    + +
      +
    • puede ser que tu programa igual ande perfecto (en el primer caso la variable anónima funciona igual que una común), ó bien
    • +
    • puede ser que por un error de tipeo tu programa no ande (qué bueno que nos avise).
    • +
    • En general, los warnings nos deberían hacer pensar si escribimos bien las variables, y si lo hicimos bien, deberíamos entonces revisar la lógica del predicado (pifiarla en eso es un error más grave)
    • +
    + + +
    + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/xtend-amigandonos-git.html b/wiki/articles/xtend-amigandonos-git.html new file mode 100644 index 0000000000..f610192143 --- /dev/null +++ b/wiki/articles/xtend-amigandonos-git.html @@ -0,0 +1,420 @@ + + + + + + + + + + + Xtend - control de versiones + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Xtend - control de versiones +

    +
    + + + + + +
    +

    No todos los archivos deben subirse al repo. Como regla general no deberían subir archivos que se puedan generar a partir de otros, por ejemplo:

    + +
      +
    • los archivos .java que se generan a partir del código Xtend (en target/xtend-gen/main)
    • +
    • los binarios que se generan a partir del código fuente de ustedes (en target/classes). Ocupan espacio en el repositorio y se corre el riesgo de estar trabajando con versiones desactualizadas.
    • +
    • archivos de configuración propios de Eclipse, como .project, .classpath y el directorio .settings. Todos estos se generan a partir del pom.xml cuando hacemos Maven > Update, y por este motivo no es bueno trabajar con los archivos de Eclipse ni tenerlos en cuenta en el control de versiones.
    • +
    + +

    Cómo no subir esos archivos

    + +

    Debemos crear un archivo .gitignore (que en Wollok se los creó el propio entorno), en la carpeta raíz del proyecto, que debe tener al menos esta lista:

    + +
    +
    +
    +      /target/
    +.classpath
    +.project
    +bin
    +generated*
    +.settings
    +
    +    
    +
    +
    + +

    Fíjense que hemos eliminado todos los archivos que se pueden generar en base a definiciones originales. Esto da como resultado un repositorio con menos cantidad de archivos y mayor calidad de los mismos. Por lo general, deberíamos evitar subir archivos binarios (salvo imágenes o archivos encriptados con información sensible), dado que ocupan más espacio y no se puede comparar diferencias entre versiones, solo saber si cambió.

    + +

    Recomendaciones para trabajar con mi grupo

    + +
      +
    • Cuando empiezo el día primero sincronizo el repositorio para ver los cambios que no tengo en el código. Si no hay cambios, simplemente corro los tests y empiezo a codear como un campeón. Si no… +
        +
      • Acepto los cambios entrantes y en caso de ser necesario resuelvo conflictos
      • +
      • Corro los tests y veo que todo anda sobre ruedas
      • +
      • Vuelvo a sincronizar y veo que ya no quedan ni conflictos ni cambios sin aceptar
      • +
      • Subo mis cambios al repositorio remoto para que mis compañeros lo vean
      • +
      +
    • +
    • Ahora sí, a programo, programo, programo… y cuando termino, corro los tests
    • +
    • Y vuelvo a sincronizar contra el repositorio remoto
    • +
    + +

    En resumen:

    + +
      +
    • No pasa un día de trabajo sin hacer un commit y push al repositorio remoto. Esto implica planificar mi trabajo para que pueda subir algo al repositorio sin que rompa todo: hay que partir un cambio grande en pequeños pasos (iterativo, incremental).
    • +
    • Nunca deberían subir nuevos fuentes al repositorio sin explicar brevemente qué cambiaron. Si los mensajes son descriptivos (y “fix”, “asdsadsa” o “arreglo una cosita” definitivamente no lo son) rápidamente puedo detectar qué modificaron mis compañeros con sólo leer lo que escribieron en los commits. Una buena descripción me ayuda también a entender qué es lo que se modificó y por qué razón, especialmente útil a la hora de solucionar un conflicto o entender por qué se rompieron los tests.
    • +
    • El que rompe los tests paga las facturas.
    • +
    + +

    Metodología para trabajar en grupo

    + +
      +
    • los tests tienen que estar en verde siempre
    • +
    • los tests son de todos y todos somos responsables por mantenerlos
    • +
    • si encontramos un bug y no había un test que lo probaba agregamos uno
    • +
    • los tests son rápidos de correr (no pueden tardar 10 minutos)
    • +
    + +

    Git por consola o Git con una herramienta visual?

    + +

    Da lo mismo, elegí la herramienta que mejor te resulte. eGit no es la gran cosa y hay otras opciones (tenés los links en la página), lo importante es cómo te organizás con tus compañeros.

    + +
    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/xtend-creacion-proyecto.html b/wiki/articles/xtend-creacion-proyecto.html new file mode 100644 index 0000000000..1a6ec0428c --- /dev/null +++ b/wiki/articles/xtend-creacion-proyecto.html @@ -0,0 +1,497 @@ + + + + + + + + + + + Cómo generar un proyecto Xtend nuevo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Cómo generar un proyecto Xtend nuevo +

    +
    + + + + + +
    +

    Para realizar las prácticas, vas a crear un proyecto desde cero. Como ahora hay muchas más opciones, te dejamos una guía simple de cómo iniciarte.

    + +

    Crear proyecto Maven

    + +

    Todos los ejemplos que vas a descargar de la materia, así como los proyectos en los que vas a trabajar, se basan en la tecnología Maven. Para crear un proyecto Maven, te dejamos esta animación:

    + +

    + image +

    + +
      +
    • Seleccionamos New > Project… Maven Project
    • +
    • Chequeamos “Skip archetype selection” ya que no lo usaremos, y luego Next
    • +
    • En la siguiente pantalla, escribimos cualquier cosa en “groupId”, que es un valor que luego borraremos, pero que si lo dejamos vacío Eclipse nos mostrará un error. Y el nombre de nuestro proyecto o artifactId, éste sí es importante, seguimos la nomenclatura de paquetes de Java, para que no haya confusiones en los nombres: ar.edu.unsam.prueba identifica nuestro proyecto en todo el mundo
    • +
    • cuando finalizamos, se genera un proyecto con un archivo pom.xml, que es fundamental para que Eclipse regenere el proyecto en otra máquina y descargue las dependencias
    • +
    + +

    Configuración de un proyecto Maven

    + +

    El acrónimo POM es por “Project Object Model”. El archivo pom.xml es el core de la configuración de un proyecto maven. Es un solo archivo de configuración que contiene la mayoría de la información requerida para el build de un proyecto.

    + +

    Pom, pom, pom, pom…

    + +

    Para comenzar a escribir la configuración del proyecto en un archivo pom.xml existen algunas opciones:

    + +
      +
    • Inicializar un proyecto maven desde 0 desde la terminal con el comando mvn archetype:generate. Al hacer esto maven nos pedirá los datos iniciales para inicializar el proyecto (artifactId, groupId, etc) y nos dejará un pom.xml creado y listo para usar/modificar.
    • +
    • Crear un proyecto maven desde eclipse u algún otro IDE.
    • +
    • Copiarse un pom.xml de un proyecto maven existente y adecuar los valores de los campos que identifican el proyecto.
    • +
    + +

    Te dejamos entonces el modelo de proyecto Maven por defecto para la cursada de Algoritmos 2 (UNSAM) del aǹo 2021: pom.xml de ejemplo. Luego tendrás que

    + +
      +
    • renombrar el archivo a pom.xml
    • +
    • copiarlo dentro del directorio raíz de tu proyecto ya creado
    • +
    • actualizar en base a los nombres de tu proyecto (el artifactId y groupId)
    • +
    • revisar las dependencias
    • +
    + +

    Para profundizar un poco más sobre lo que contiene un archivo de Maven, te recomendamos este artículo.

    + +

    Sincronización entre Eclipse y Maven

    + +

    Cada vez que hagamos un cambio en el archivo pom.xml, nos aparecerá un mensaje de error en la solapa Problems, que se soluciona forzando la sincronización entre Eclipse y Maven (dado que cada uno maneja su propia estructura de proyectos Java). Como regla general, siempre que necesitemos agregar alguna biblioteca, o dependencia, debemos hacerlo en el archivo pom y no desde las opciones que ofrece el Eclipse, porque nuestros compañeros o los docentes no tendrán esa biblioteca. Para sincronizar Maven y Eclipse, nos paramos en el proyecto y con un botón derecho elegimos “Maven > Update Project”.

    + +

    Primeros pasos

    + +

    + image +

    + +

    Ahora solo nos queda eliminar la línea groupId (con Ctrl + D), formatear el pom.xml (con Ctrl + Shift + F) y crear nuestra primera clase Perro. Es importante notar que tendremos dos carpetas donde ubicaremos los fuentes:

    + +
      +
    • src/main/java: donde irán las clases
    • +
    • src/test/java: donde irán los tests
    • +
    + +

    Por eso, nos ubicamos en src/main/java y con un botón derecho, New > Xtend Class (es importante que hayas configurado el Eclipse para que no esté escondida esta opción).

    + +

    Generación de archivos .java

    + +

    En src/main/generated-sources vas a tener los archivos .java que se generan en base a los archivos de xtend. ¡No los toques! Porque cada cambio que hagas en tu clase xtend va a pisar los cambios de los archivos .java. En general no deberías mirar nunca el java que genera, porque además utiliza construcciones menos simples que si programaras directamente en java.

    + +

    Recomendaciones

    + +

    A continuación te dejamos algunas recomendaciones para que tu estadía en Eclipse + Xtend sea más feliz:

    + +
      +
    • ¡Formatear el código! Nunca nos olvidemos de que nuestro código tiene que ser entendible para el resto de la humanidad. Además, el Eclipse lo hace solo (Ctrl + Shift + F).
    • +
    + +

    + image +

    + +
      +
    • Utilización de packages (paquetes). Es una buena práctica agrupar las clases afines en paquetes para organizar semánticamente el código. No hay una guía firme a seguir con respecto a cómo organizar nuestro código, ya que suele depender del contexto en el cual estamos trabajando, pero a medida que veas nuestros ejemplos y vayas haciendo las prácticas notarás que hay clases que se pueden agrupar en contextos similares. Te dejamos un ejemplo
    • +
    + +
    +
    +
    +      proyecto
    +   ├── home
    +   ├── registration
    +   │   ├── Profile.xtend
    +   │   └── User.xtend
    +   └── settings
    +       ├── CustomPrivacy.xtend
    +       ├── DefaultPrivacy.xtend
    +       ├── Privacy.xtend
    +       └── Setting.xtend
    +
    +    
    +
    +
    + +

    De esta manera, logramos mayor granularidad en la organización de nuestras clases. +___

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/xtend-guia-rapida.html b/wiki/articles/xtend-guia-rapida.html new file mode 100644 index 0000000000..ed3d81b89a --- /dev/null +++ b/wiki/articles/xtend-guia-rapida.html @@ -0,0 +1,1219 @@ + + + + + + + + + + + Guia rapida de Xtend + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Guia rapida de Xtend +

    +
    + + + + + +
    +

    La siguiente es una guía de syntactic sugars de Xtend, algunos de los cuales trabajan conceptos más profundos que veremos a lo largo de la materia.

    + +

    Definición de una clase

    + +

    No tenemos objetos en Xtend, sólo clases. Aquí dejamos un ejemplo

    + +
    +
    +
    +      class Ave {
    +    static int ENERGIA_MINIMA = 10
    +    @Accessors int energia = 0
    +    def volar() { energia = energia - 10 }
    +    def comer(int cuanto) { energia = energia + (cuanto * 2) }
    +    def esFeliz() { energia > ENERGIA_MINIMA }
    +    def resetearEnergia() { energia = 0 }
    +}
    +
    +    
    +
    +
    + +
      +
    • podemos escribir múltiples clases en un archivo Xtend
    • +
    • la definición de la clase se encierra entre llaves
    • +
    • la variable ENERGIA_MINIMA es estática, esto significa que todas las instancias comparten la misma variable (lo que también se llama variable de clase), suele usarse como constantes o valores que difícilmente cambien.
    • +
    • la variable energia es una variable de instancia porque cada objeto Ave tiene su propio valor.
    • +
    • las variables de instancia y de clase deben anotarse con el tipo, en este caso ambos son int
    • +
    • la variable energia tiene la anotación @Accessors, que permite definir getters y setters automáticos
    • +
    • los métodos volar, comer y esFeliz necesitan la palabra def para indicar que son métodos. Algunos producen efecto (volar y comer) y otros simplemente devuelven un valor (esFeliz)
    • +
    • no es necesaria la palabra return al final de cada método, pero en algunos casos veremos que es necesaria
    • +
    • no siempre es necesario hacer anotaciones de tipo sobre los métodos, como veremos más adelante
    • +
    + +

    Referencias variables y valores

    + +

    En Xtend, al igual que muchos otros lenguajes, se diferencian las referencias como

    + +
      +
    • Variables: son referencias que pueden inicializarse apuntando a un objeto, y luego reasignarse a otro. Justamente “varían”:
    • +
    + +
    +
    +
    +      var String unString = "Pepito"
    +unString = "Otro String"
    +
    +    
    +
    +
    + +
      +
    • Constantes: son referencias que nacen apuntando a un valor y no pueden ser modificadas para apuntar a otro objeto. Serían como “constantes”.
    • +
    + +
    +
    +
    +      val String constante = "Constante"
    +constante = "Otro"  // <----- NO COMPILA !
    +
    +    
    +
    +
    + +

    ¡Ojo! no confundir el hecho de que no se pueda modificar la “referencia” de la mutabilidad/inmutabilidad del objeto al que apunta. Puedo tener un “val” apuntando a una colección, que es mutable.

    + +
    +
    +
    +      val List miLista = unaLista
    +miLista = otraLista  // <----- NO COMPILA: no puedo modificar la referencia
    +miLista.add(23)      // <---- SI COMPILA: puedo mandarle mensajes al objeto lista y agregarle elementos
    +
    +    
    +
    +
    + +

    Cuándo debería usar val y cuándo var

    + +
      +
    • las variables de instancia siempre son variables, de lo contrario no tiene sentido definirlas como tal
    • +
    • los valores constantes se suelen definir como variables de clase o static
    • +
    • respecto a las variables locales, en la cursada las usaremos pocas veces: primero intentaremos definirlas como val y de no ser posible, como var. El motivo principal es acotar el efecto en nuestros programas, mientras menor sea el efecto, más fácil es controlar nuestro software, y más fácil será testearlo.
    • +
    + +

    Tipos de datos

    + +

    Strings

    + +

    Un string se encierra entre dobles comillas, o bien podemos aprovechar para escribir un texto largo con enters con triples comillas simples, e insertar en el medio código Xtend mediante

    + +
    +
    +
    +      class Cliente {
    +    var nombre = "Juan" // definición con comillas dobles
    +
    +    def presentacion() {
    +        '''
    +        Bienvenido, «nombre.trim()» a nuestra aplicación.
    +        En breve nos contactaremos con ud.
    +        '''
    +    }
    +}
    +
    +    
    +
    +
    + +
    +

    Tip: para que te aparezcan los símbolos «» que son difíciles de encontrar en el teclado, simplemente utilizá las teclas Ctrl + Espacio dentro de la definición del string y aparecerán solas

    +
    + +

    Números

    + +

    Existen muchos tipos de datos diferentes para números:

    + +
      +
    • int: es un número entero que admite negativos pero sin decimales
    • +
    • double, float: son números reales que admiten decimales pero con errores en las operaciones, es por ello que no debemos usarlo para operaciones sensibles (como transacciones bancarias o que requieran cálculos exactos)
    • +
    • BigDecimal: es el tipo de dato que conviene utilizar ya que no produce errores de redondeo (permite trabajar con una cantidad exacta de decimales y truncarlos o redondearlos en caso de ser necesario)
    • +
    • También existen las variantes “objetosas” de int, double y float que son Integer, Double y Float. La principal ventaja es que son objetos, y podemos enviarle mensajes (concretamente más mensajes) que a las versiones en minúscula, que son tipos primitivos. Es posible “envolver” en una variable Integer cualquier int, la conversión se da automáticamente por el compilador de Java y se llama “autoboxing”:
    • +
    + +
    +
    +
    +      var i = 0                         // int
    +var pi = 3.14d                    // double
    +var saldo = new BigDecimal(1500)  // BigDecimal
    +var Integer otroI = i             // otroI es un entero
    +otroI.bitwiseNot                  // puedo enviar un mensajes
    +
    +    
    +
    +
    + +

    Colecciones

    + +

    Existen literales para definir listas, conjuntos y mapas (dictionaries):

    + +
    +
    +
    +      // Lista inmutable:
    +val myList = #['Hello', 'World']
    +// Set inmutable
    +val mySet = #{'Hello', 'World'}
    +// Mapa/Diccionario inmutable
    +val myMap = #{'a' -> 1 , 'b' ->2}
    +
    +    
    +
    +
    + +

    Recordemos que

    + +
      +
    • listas: respetan el orden en el que se agregan (como una fila) y admiten duplicados.
    • +
    • conjuntos: no tienen orden y tampoco admiten duplicados. Dos objetos son iguales en base a la definición de equals() y hashCode().
    • +
    • mapas: también llamados dictionaries, son un conjunto de pares clave/valor. Se acceden por clave.
    • +
    + +

    Range

    + +

    Es posible generar un rango de números, por ejemplo para iterar una cantidad de veces:

    + +
    +
    +
    +      #[1 .. 10].forEach [ ... ]      // [1..10] genera la lista de 1 a 10
    +#[1 ..< 10].forEach [ ... ]     // [1..<10] genera la lista de 1 a 9
    +#[1 >.. 10].forEach [ ... ]     // [1>..10] genera la lista de 2 a 10
    +
    +    
    +
    +
    + +

    ..< es útil cuando necesitás iterar una lista de Java, que comienza en 0 y termina en (longitud - 1):

    + +
    +
    +
    +      #[0 ..< lista.size].forEach [ i | println(i) ]
    +
    +    
    +
    +
    + +

    Literales para lista, conjunto, etc.

    + +

    Xtend trae shortcuts para definir diferentes tipos de colecciones:

    + +
    +
    +
    +      List<Factura> facturas = newArrayList
    +Set<Domicilio> domicilios = newHashSet
    +List<String> nombres = newArrayList("nahuel", "rodrigo", "marina")
    +
    +    
    +
    +
    + +

    Podés utilizar newLinkedList, emptyList, emptySet, emptyMap, newInmutableMap, newImmutableSet, newImmutableList, newLinkedHashSet, newTreeSet, newHashMap, newLinkedHashMap, newTreeMap. La ventaja que tienen es que permiten pasarle parámetros variables (tantos como elementos necesites) y trae implementaciones por defecto para algunas colecciones que necesitan comparators (tenés que estudiar más a fondo Colecciones en Xtend)

    + +

    Inferencia de tipos

    + +

    Xtend cuenta con inferencia de tipos, lo que permite

    + +
      +
    • que existan chequeo de tipos
    • +
    • pero que la mayoría de las veces no sea necesario definir los tipos de las expresiones
    • +
    + +

    Vemos un ejemplo en vivo, mostrando cómo cambia la solapa “Outline” cuando modificamos el código:

    + +

    + image +

    + +

    Aquí vemos que incluso Xtend detecta expresiones que no tienen sentido, como cuando hicimos:

    + +
    +
    +
    +      def esFeliz() {
    +    energia > ENERGIA_MINIMA
    +    "si"
    +}
    +
    +    
    +
    +
    + +

    El hecho de generar una expresión energia > ENERGIA_MINIMA no causa efecto en el objeto y tampoco se devuelve (porque se pisa por la expresión “si” que es devuelta como retorno del método).

    + +

    Volviendo a la inferencia de tipos, es fundamental poder contar con un lenguaje que tenga chequeo de tipos para detectar errores en forma temprana pero que no me obligue a definir los tipos todo el tiempo. La definición de tipos es obligatoria para las variables de instancia y de clase de los objetos, y en algunos casos cuando la definición de métodos polimórficos puede resultar ambigua para Xtend. En cualquiera de esos casos vas a ver un mensaje de error o de advertencia para que definas el tipo que mejor se ajuste.

    + +

    Casteos

    + +

    Si bien toda expresión tiene un tipo y Xtend suele inferirlo bastante bien, a veces es necesario hacer downcasting o forzar que una expresión pase por un tipo de datos:

    + +
    +
    +
    +      (42 as Integer)
    +(cliente as Cliente)
    +
    +    
    +
    +
    + +

    En general la expresión es, entre paréntesis: (valor/variable as tipo)

    + +

    Definición de propiedades

    + +

    La anotación @Accessors puede hacerse sobre una variable, como hemos visto antes:

    + +
    +
    +
    +      class Ave {
    +    @Accessors int energia = 0
    +
    +    
    +
    +
    + +

    En este caso se crean getters y setters para energia, transformándolo en una propiedad.

    + +
    +
    +
    +      class Ave {
    +    @Accessors(PUBLIC_GETTER) int energia = 0
    +
    +    
    +
    +
    + +

    En este caso se crea un getter público para la variable energia. Otras variantes son: crear sólo un setter público o crear getters o setters con diferentes visibilidad.

    + +

    Por último, podemos anotar la clase con @Accessors

    + +
    +
    +
    +      @Accessors
    +class Ave {
    +    int energia = 0
    +    int vecesQueVolo = 0
    +
    +    
    +
    +
    + +

    en este caso, se crean getters y setters para todas las variables de dicha clase.

    + +

    Shortcut para acceder a propiedades

    + +

    Cuando usamos un objeto que tiene propiedades (par getter y setter), podemos cambiar un poco la sintaxis para que se vea más simple. En el ejemplo anterior del Ave:

    + +
    +
    +
    +      val pepita = new Ave()
    +pepita.energia = 100    // <-- equivale a pepita.setEnergia(100)
    +pepita.energia          // <-- equivale a pepita.getEnergia()
    +
    +    
    +
    +
    + +

    ¡Ojo! si bien parece que estamos accediendo diréctamente a la variable de instancia, no es así. Xtend simplemente traduce esa sintaxis a la anterior. Es decir que en ambos casos estamos igualmente llamando al getter y al setter. Pueden probar eliminando la anotación @Accessors y recibiremos un mensaje “The field energia is not visible”.

    + +

    Paréntesis en el envío de mensajes

    + +

    No es necesario utilizar paréntesis, ni en la creación de objetos, ni en el envío de mensajes sin parámetros:

    + +
    +
    +
    +      val golondrina = new Ave
    +golondrina.resetearEnergia
    +
    +    
    +
    +
    + +

    Herencia y redefinición de métodos

    + +

    A continuación vemos cómo definir dos subclases de Ave: Golondrina y Torcaza.

    + +

    + image +

    + +
    +
    +
    +      @Accessors
    +class Ave {
    +    int energia = 0
    +    static int ENERGIA_MINIMA = 10
    +    def volar() { energia = energia - 10 }
    +    def comer(int cuanto) { energia = energia + (cuanto * 2) }
    +    def esFeliz() { energia > ENERGIA_MINIMA }
    +}
    +
    +class Golondrina extends Ave {
    +    override esFeliz() { true }
    +}
    +
    +class Torcaza extends Ave {
    +    int vecesQueVolo = 0
    +
    +    override volar() {
    +        super.volar()
    +        vecesQueVolo++
    +    }
    +}
    +
    +    
    +
    +
    + +

    Aquí vemos que

    + +
      +
    • Golondrina y Torcaza heredan de Ave, indicado mediante la palabra clave extends
    • +
    • Golondrina redefine el comportamiento de esFeliz, lo pisa, y esto requiere la palabra clave override (no funciona si intentamos definirlo con def)
    • +
    • Torcaza también lo redefine, pero fuerza a llamar al comportamiento de la superclase mediante la palabra clave super, indicando luego el mensaje a aplicar. Como regla general solo deben utilizar super cuando no puedan utilizar self, como en este caso (entrarían en loop infinito)
    • +
    + +

    Clases y métodos abstractos

    + +

    Podemos definir a Ave como clase abstracta, esto producirá que no podamos instanciar objetos Ave. Una clase abstracta puede definir solo la interfaz de un método, lo que se conoce como método abstracto. Veamos el siguiente ejemplo:

    + +

    + image +

    + +

    En el ejemplo:

    + +
      +
    • primero definimos Ave como abstracta
    • +
    • eso provoca que el compilador Xtend tire un error cuando queremos instanciar un Ave en la clase Ornitologo
    • +
    • lo corregimos instanciando una Golondrina
    • +
    • luego, queremos definir un método abstracto: esFeliz. Para ello reemplazamos la definición por una cáscara que solo dice que esFeliz debe devolver un booleano. Dado que no hay código Xtend nos fuerza a definir el tipo de retorno del método (y de sus parámetros) porque no puede inferirlo.
    • +
    • todos los métodos abstractos deben estar implementados en las subclases: el compilador nos avisa que falta la definición de esFeliz() en Torcaza. Con un botón derecho “Add unimplemented methods” pegamos la definición copiada.
    • +
    • como nos falta la constante que estaba en Ave, la bajamos mediante Alt + Flecha abajo
    • +
    + +

    y finalmente todo compila.

    + +

    Constructores

    + +

    Un constructor se define con la palabra reservada new (equivalente al constructor de Wollok):

    + +
    +
    +
    +      @Accessors
    +class Golondrina {
    +    int energia
    +    new() {
    +        this(100)   // llama al constructor con parámetros
    +        // para llamar al constructor de la superclase es necesario utilizar super(params)
    +    }
    +    new(int energia) {
    +        this.energia = energia
    +    }
    +}
    +
    +    
    +
    +
    + +
      +
    • Por defecto, si no hay constructores se genera uno por defecto sin parámetros y no hace falta definirlo
    • +
    • Es posible definir múltiples constructores, como vemos en el ejemplo, con diferente cantidad de parámetros o de tipos
    • +
    • Cuando definimos constructores sobre una clase, se pierde el constructor por defecto
    • +
    • Los constructores de Xtend no se heredan
    • +
    + +

    Bloques

    + +

    Un bloque permite definir una porción de código, también llamada expresión lambda:

    + +
    +
    +
    +      val cuadrado = [ int num | num ** 2 ]
    +cuadrado.apply(5)
    +
    +    
    +
    +
    + +

    De esta manera podemos enviar bloques como parámetros, algo muy útil para trabajar entre otras cosas con las colecciones (map, filter, fold, etc.)

    + +

    La sintaxis general es

    + +
    +
    +
    +      [ | ... ]                // bloque sin parámetros
    +[ elem | ... ]           // bloque con un parámetro
    +[ int a, int b | a + b ] // bloque con dos parámetros
    +
    +    
    +
    +
    + +

    Variable implícita it

    + +

    De la misma manera que cuando estamos dentro de una clase, podemos acceder a una variable de instancia con this

    + +
    +
    +
    +      this.energia
    +
    +    
    +
    +
    + +

    o sin él:

    + +
    +
    +
    +      energia
    +
    +    
    +
    +
    + +

    también podemos usar una variable implícita it dentro de un método.

    + +
    +
    +
    +      val it = new Ave()
    +volar       // equivale a it.volar()
    +comer(2)    // equivale a it.comer(2)
    +
    +    
    +
    +
    + +

    Dentro de una expresión lambda, it es la variable implícita del primer parámetro, por lo tanto todas estas expresiones son equivalentes:

    + +
    +
    +
    +      alumnos.filter [ alumno | alumno.estudioso() ]
    +alumnos.filter [ it | it.estudioso() ]
    +alumnos.filter [ it.estudioso() ]
    +alumnos.filter [ it.estudioso ]
    +alumnos.filter [ estudioso ]
    +
    +    
    +
    +
    + +

    + image +

    + +

    Manejo de nulls

    + +

    Los valores nulos son siempre un dolor de cabeza, Xtend tiene algunos trucos para facilitar un poco más el trabajo con ellos.

    + +

    Elvis operator

    + +

    Parece un emoticón, pero ?: es un shortcut para utilizar un valor por defecto cuando una expresión pueda ser nula:

    + +
    +
    +
    +      val nombre = person.firstName ?: 'You'
    +
    +    
    +
    +
    + +

    Si la expresión que está a la izquierda se evalúa como null, nombre se asigna a la segunda expresión.

    + +

    Null safe operator

    + +

    También podemos resolver envíos de mensajes a referencias que potencialmente podrían ser nulas:

    + +
    +
    +
    +      val mejorAlumno = alumnos.find [ ... ]
    +...
    +mejorAlumno?.felicitar()
    +
    +    
    +
    +
    + +

    En este caso, el operador ?. es equivalente a preguntar if (mejorAlumno) mejorAlumno.felicitar()

    + +

    Comparar referencias

    + +

    Después de varios cambios, Xtend dejó las cosas como la mayoría de los lenguajes. Tenemos dos formas de comparar referencias:

    + +
    +
    +
    +      ref1 == ref2     // compara por igualdad, esto significa que son iguales si son las referencias
    +                 // apuntan al mismo objeto o bien, en base a la definición del método equals
    +                 // en la clase ref1 (sabiendo que ref1 no es nulo)
    +                 // en la clase asociada a ref1
    +ref1 === ref2    // compara por identidad, esto significa que son iguales si las referencias
    +                 // apuntan al mismo objeto en memoria, determinado por la VM y no se puede cambiar
    +
    +    
    +
    +
    + +

    Tener especial atención a los strings, ya que dos strings con el mismo contenido pueden ser iguales pero no idénticos, dependiendo de las estrategias de optimización de la VM. Siempre es conveniente utilizar ==, que además se puede modificar.

    + +

    Métodos avanzados

    + +

    Obligatoriedad del return en métodos

    + +

    Por lo general, los métodos devuelven la última expresión que contienen. Pero a veces es necesario cortar el flujo de envío de mensajes, como por ejemplo aquí:

    + +
    +
    +
    +      def gradoDeFelicidad() {
    +    if (!esFeliz) {
    +       return 0
    +    }
    +    ... cálculo complejo ...
    +}
    +
    +    
    +
    +
    + +

    Para determinar el grado de felicidad de alguien, tenemos como precondición que sea feliz. Y para simplificar la definición, escribimos el if y forzamos el return (dado que escribir únicamente 0 no tendrá efecto, porque Xtend seguirá evaluando el resto de las expresiones hasta terminar la última y nosotros queremos justamente cortar el flujo).

    + +

    En el caso de un método que solo busque producir un efecto (void), es necesario utilizar return; con punto y coma…

    + +
    +
    +
    +      def metodoConEfecto() {
    +    ... cambios ...
    +    if (!situacion) {
    +       return;
    +    }
    +    ... otros cambios ...
    +}
    +
    +    
    +
    +
    + +

    Igualmente, siempre es preferible tratar de extraer métodos más pequeños para simplificar la lógica.

    + +

    Extension methods

    + +

    Una de las herramientas más poderosas consiste en definir extension methods. Supongamos que un negocio tiene un horario de apertura y de cierre y queremos saber, dada una hora, si está abierto.

    + +
    +
    +
    +      class Negocio {
    +    int horarioApertura
    +    int horarioCierre
    +
    +    def estaAbierto(int horaActual) {
    +        horaActual.between(horarioApertura, horarioCierre)
    +    }
    +}
    +
    +    
    +
    +
    + +

    Por supuesto, no compila. No existe el método between asociado a los enteros. Pero en otro archivo vamos a definir un método estático (no asociado a un objeto):

    + +
    +
    +
    +      class NumberUtils {
    +    static def between(int num, int from, int to) {
    +        num >= from && num <= to
    +    }
    +}
    +
    +    
    +
    +
    + +

    Y ahora, desde el archivo Negocio.xtend, vamos a importar el método como static extension:

    + +

    + image +

    + +

    El código a agregar es

    + +
    +
    +
    +      // después de la definición de package
    +import static extension ar.edu.unsam.prueba.NumberUtils.*
    +
    +    
    +
    +
    + +

    Esto produce que automáticamente, el compilador Xtend marque en naranja el método between y nuestra clase Negocio compile perfectamente. En resumen, un extension method permite que nosotros agreguemos comportamiento por afuera de la definición de una clase como si estuviéramos trabajando en ella, algo muy importante cuando la clase no podemos modificarla (como en el caso de Integer , String), o bien cuando se está regenerando todo el tiempo (cuando tenemos un framework que genera código para nosotros), sin contar que además estamos respetando la idea de mensaje (y por consiguiente, la posibilidad de seguir trabajando con polimorfismo).

    + +

    Los métodos map, filter, fold, length, any, etc. son todos extension methods de Collections.

    + +

    Dispatch methods

    + +

    Xtend permite trabajar con multimethods, más adelante tendremos este ejercicio para contarlo con más profundidad

    + +

    @Data

    + +

    Para definir un objeto inmutable, debemos:

    + +
      +
    • generar una clase
    • +
    • con atributos privados
    • +
    • y un constructor donde pueda asignar ese estado
    • +
    + +

    Xtend provee la anotación @Data para lograr eso:

    + +
    +
    +
    +      @Data
    +class Point {
    +    int x
    +    int y
    +}
    +
    +    
    +
    +
    + +

    Esto equivale a definir el constructor con dos parámetros (x, y) y los getters para los atributos x e y, sin setters (dado que queremos únicamente representar un valor). Por lo tanto, esta definición compila perfectamente:

    + +
    +
    +
    +      class TestPoint {
    +    def test() {
    +        new Point(2, 4).x
    +    }
    +}
    +
    +    
    +
    +
    + +

    Si por el contrario intentamos asignar el valor de x:

    + +
    +
    +
    +      new Point(2, 4).x = 2
    +
    +    
    +
    +
    + +

    nos dirá The field x is not visible.

    + +

    With operator

    + +

    Otro syntactic sugar muy interesante de Xtend es la posibilidad de enviar múltiples mensajes al mismo objeto, mediante el operador with =>, algo muy útil cuando estamos instanciando objetos:

    + +
    +
    +
    +      val ventaNacional = new Venta => [
    +    cantidadKilos = 12
    +    fechaVenta = new Date
    +    parcela = parcela50
    +    comprador = new CompradorNacional
    +]
    +
    +    
    +
    +
    + +

    De esta manera, todos los mensajes se apuntan al objeto que resulta de evaluar la expresión new Venta, y simplifica el envío de mensajes:

    + +
    +
    +
    +      ventaNacional.cantidadKilos = 12
    +ventaNacional.fechaVenta = new Date
    +ventaNacional....
    +
    +    
    +
    +
    + +

    Links relacionados

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/xtend-preparacion-de-un-entorno-de-desarrollo.html b/wiki/articles/xtend-preparacion-de-un-entorno-de-desarrollo.html new file mode 100644 index 0000000000..3aebffe0b0 --- /dev/null +++ b/wiki/articles/xtend-preparacion-de-un-entorno-de-desarrollo.html @@ -0,0 +1,548 @@ + + + + + + + + + + + Preparacion de un entorno de desarrollo xtend + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Preparacion de un entorno de desarrollo xtend +

    +
    + + + + + +
    +

    + +

    + +

    Download e instalación base

    + +

    Git Bash (sólo para Windows)

    + +

    Para simplificar el uso de Git en entornos Windows, existe la herramienta Git Bash que podés descargar a partir de esta página, haciendo click en el link “Download”.

    + +

    Si estás en Mac o Linux, podés saltear este paso.

    + +

    JDK: Java Development Kit

    + +

    Primero instalaremos el compilador de Java.

    + +

    Ingresamos a esta dirección, y descargamos la Open JDK 11, que es la versión oficial que manejamos desde 2020 y cuya licencia es GPL.

    + +

    Pasos de instalación

    + +

    Una vez descargado el binario en una carpeta (supongamos que es C:\jdk11), hay que configurar dos variables de entorno de tu sistema operativo:

    + +
      +
    • JAVA_HOME: tiene que apuntar a C:\jdk11)
    • +
    • PATH: hay que incorporarle C:\jdk11\bin (cuidando de no borrar lo que ya está)
    • +
    + +

    Te dejamos un video que explica cómo hacerlo para Windows (el procedimiento es similar para MacOS / Linux)

    + +

    Chequeos posteriores a la instalación

    + +
      +
    • Dentro de las variables de entorno de tu sistema operativo debe estar JAVA_HOME asignada. En Linux / Mac esto es env | grep JAVA_HOME, y en Windows SET JAVA_HOME. Si la variable no está seteada, eso significa que te salteaste un paso, lo mismo si la carpeta que muestra JAVA_HOME no es la que contiene la versión que vos descargaste. En ese caso volvé al punto anterior y seguí nuevamente las instrucciones para encontrar lo que está faltando.
    • +
    • En una ventana de línea de comandos, verificar la versión de java instalada con java -version, y el compilador mediante javac -version. En ambos casos mostrará la versión por defecto para tu máquina. Si no aparece la versión que descargaste, el sistema operativo asume por defecto otra instalación, que podría ser incluso de una JRE (ver más abajo). En ese caso, revisá el link del punto anterior para ver qué puede estar faltando y repetí los pasos.
    • +
    + +

    JDK sí, JRE no

    + +
    +

    IMPORTANTE: tenés que instalar una JDK, no una JRE (Java Runtime Environment) que solo te permite ejecutar programas Java ya compilados. Para saber si tenés una JDK, deberías ir al directorio de instalación y en la carpeta bin debe estar un programa llamado javac, que es el compilador de Java.

    +
    + +

    + image +

    + +

    Si no tenés ese programa, no vas a poder pasar tus objetos a código ejecutable en el entorno Xtend: la solución es muy simple, descargá e instalá una JDK. Para más información te recomendamos esta página

    + +

    Eclipse

    + +

    Nuestro entorno integrado de desarrollo (IDE) permite que en una misma herramienta editemos nuestro código fuente, compilemos, hagamos pruebas, y muchas cosas más. En Algoritmos 1 ya conociste Eclipse, con un entorno modificado especialmente para soportar el lenguaje Wollok. Aquí lo utilizaremos con diferentes plugins, pero seguramente te resultará familiar la forma de trabajar.

    + +

    Pasos de instalación

    + +

    Tenés que descargarlo desde esta página utilizando el link más reciente de Eclipse (al 01/03 es Get Eclipse IDE 2020‑12)

    + +
    +

    NOTA: podés visitar la página histórica de descarga de Eclipses anteriores por si hay versiones más nuevas y te interesa usar la versión 2020-12 que es con la que desarrollamos los ejemplos. Normalmente las actualizaciones de Eclipse siguen funcionando sin mayores problemas con el plugin de Xtend, Java y Maven.

    +
    + +

    Eso te descarga un eclipse-installer, que es el primer paso. Lo abrís con un doble click, y luego seleccionás

    + +
      +
    • si estás cursando Programación con Herramientas Modernas: “Eclipse IDE for Enterprise Java Developers”
    • +
    • cualquier otra cursada: “Eclipse for Java Developers”, seleccionando la carpeta de destino.
    • +
    + +

    Chequeos de instalación

    + +

    Una vez que lo hayas descomprimido en una carpeta, podés hacer un acceso directo al eclipse o eclipse.exe y ejecutarlo con doble click. Necesitarás definir un espacio de trabajo o workspace, que es la carpeta donde vas a ubicar todos tus proyectos.

    + +

    Configuraciones adicionales

    + +

    Por lo general no es necesario hacer nada más, pero en caso de necesitarlo, en la carpeta raíz donde descargaste el Eclipse vas a encontrar un archivo eclipse.ini que permite configurar

    + +

    f- cuál es la versión de Java requerida (por defecto es 1.11 y no debería ser necesario modificarla)

    +
      +
    • cuál es la ubicación donde está el ejecutable de Java: es importante que apunte a una JDK y no a una JRE, como hemos comentado en la instalación de la JDK. Si por defecto instalaste una JRE, tu Eclipse no será capaz de compilar, recomendamos volver a la página JDK y reinstalar Java. De la misma manera, la JDK a la que apunte Eclipse debería ser la misma que vos instalaste: asegurate de que estén sincronizadas.
    • +
    + +

    A continuación te dejamos un archivo .ini de ejemplo, ignorando las primeras líneas:

    + +
    +
    +
    +      ...
    +--launcher.appendVmargs
    +-vm
    +/usr/lib/jvm/java-11-openjdk-amd64/bin
    +-vmargs
    +-Dosgi.instance.area.default=@user.home/eclipse-workspace
    +-XX:+UseG1GC
    +-XX:+UseStringDeduplication
    +--add-modules=ALL-SYSTEM
    +-Dosgi.requiredJavaVersion=1.11
    +-Dosgi.dataAreaRequiresExplicitInit=true
    +-Xms512m
    +-Xmx1768m
    +--add-modules=ALL-SYSTEM
    +-Declipse.p2.max.threads=10
    +-Doomph.update.url=http://download.eclipse.org/oomph/updates/milestone/latest
    +-Doomph.redirection.index.redirection=index:/->http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/
    +
    +    
    +
    +
    + +

    En el ejemplo estamos configurando una memoria inicial de 512 MB y una memoria máxima de 1768 MB, una JDK 1.11 requerida. El resto son valores por defecto que te va a crear el instalador de Eclipse.

    + +

    Maven

    + +

    Seguí los pasos de instalación de esta página

    + +

    Plugin Xtend

    + +

    Instalá el plugin de Xtend desde el Update Site, siguiendo estos pasos:

    + +
      +
    • En el menú de Eclipse, Help > Install New Software … botón Add
    • +
    • +

      En la ventana de diálogo Add Repository, en el nombre escribir algo como “Xtend Plugin” y en Location copiar esta URL: http://download.eclipse.org/modeling/tmf/xtext/updates/milestones/

      +
    • +
    • A partir del 2021 se estará usando la versión 2.25, en caso de que vayan saliendo nuevas versiones, se puede elegir qué versión instalar destildando la opción “Show only the latest versions of available software” (más abajo está resaltado en la imagen). En caso de duda sobre qué versión instalar, aconsejamos consultar por la lista de difusión al docente responsable.
    • +
    • Seleccionar el check Xtext, y luego Xtend IDE, hacer click en Next y luego en Finish
    • +
    + +

    + image +

    + +
      +
    • Reiniciar el Eclipse
    • +
    + + + +

    Configuraciones default del eclipse

    + +

    Antes que nada chequeá las Configuraciones generales para cualquier Eclipse

    + +

    ¿Cómo empezar?

    + +
      +
    • Crear un proyecto Maven (si no instalaste Maven hacelo como se sugiere aquí +
        +
      • en la primera ventana, clickear en la opción “Create a simple project (Skip archetype selection)”, luego Next…
      • +
      • definir un groupId, que puede ser el materia . Ej: algo2, phm, etc.
      • +
      • definir un artifactId, que se asocia al nombre de tu proyecto
      • +
      +
    • +
    • Para definir el archivo pom.xml de Maven con el que vas a configurar tu proyecto, podés basarte en el modelo de ejemplo de esta página
    • +
    + + + +

    Tips

    + +
      +
    • Para que cuando hagas New > File te aparezcan las clases y las interfaces Xtend, Window > Customize Perspective… > solapa Menu Visibility > expandís File > New > y seleccionás las de Xtend (Xtend class, inteface, annotation y enum).
    • +
    + + + +

    Documentación

    + + + + + +

    Links útiles

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/articles/xtend-principal.html b/wiki/articles/xtend-principal.html new file mode 100644 index 0000000000..b219b7ab61 --- /dev/null +++ b/wiki/articles/xtend-principal.html @@ -0,0 +1,349 @@ + + + + + + + + + + + Xtend - pagina principal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    + Xtend - pagina principal +

    +
    + + + + + +
    +

    image

    + +

    A continuación te vamos a dejar los pasos de instalación del entorno Xtend para las materias Algoritmos 2, Algoritmos 3 y Programación con Herramientas Modernas. Seguí metódicamente los puntos y no saltees las verificaciones para asegurarte que en tu máquina tengas todas las herramientas necesarias para trabajar.

    + + + +
    + + + + + + + + +
    + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/internal/categories.html b/wiki/internal/categories.html new file mode 100644 index 0000000000..450a68a5b1 --- /dev/null +++ b/wiki/internal/categories.html @@ -0,0 +1,192 @@ + + + + + + + + + + + Categorias + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Descripción de categorias

    + +

    Motivación

    + +

    TODO

    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wiki/internal/featured_article.html b/wiki/internal/featured_article.html new file mode 100644 index 0000000000..04f7d2b3d4 --- /dev/null +++ b/wiki/internal/featured_article.html @@ -0,0 +1,190 @@ + + + + + + + + + + + Articulo Destacado + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Articulo Destacado

    + +

    TODO

    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000000..11165743b5 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,132 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@hapi/b64@4.x.x": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@hapi/b64/-/b64-4.2.1.tgz#bf8418d7907c5e73463f2e3b5c6fca7e9f2a1357" + integrity sha512-zqHpQuH5CBMw6hADzKfU/IGNrxq1Q+/wTYV+OiZRQN9F3tMyk+9BUMeBvFRMamduuqL8iSp62QAnJ+7ATiYLWA== + dependencies: + "@hapi/hoek" "8.x.x" + +"@hapi/boom@7.x.x": + version "7.4.11" + resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-7.4.11.tgz#37af8417eb9416aef3367aa60fa04a1a9f1fc262" + integrity sha512-VSU/Cnj1DXouukYxxkes4nNJonCnlogHvIff1v1RVoN4xzkKhMXX+GRmb3NyH1iar10I9WFPDv2JPwfH3GaV0A== + dependencies: + "@hapi/hoek" "8.x.x" + +"@hapi/bounce@1.x.x": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@hapi/bounce/-/bounce-1.3.2.tgz#3b096bb02f67de6115e6e4f0debc390be5a86bad" + integrity sha512-3bnb1AlcEByFZnpDIidxQyw1Gds81z/1rSqlx4bIEE+wUN0ATj0D49B5cE1wGocy90Rp/de4tv7GjsKd5RQeew== + dependencies: + "@hapi/boom" "7.x.x" + "@hapi/hoek" "^8.3.1" + +"@hapi/cryptiles@4.x.x": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@hapi/cryptiles/-/cryptiles-4.2.1.tgz#ff0f18d79074659838caedbb911851313ad1ffbc" + integrity sha512-XoqgKsHK0l/VpqPs+tr6j6vE+VQ3+2bkF2stvttmc7xAOf1oSAwHcJ0tlp/6MxMysktt1IEY0Csy3khKaP9/uQ== + dependencies: + "@hapi/boom" "7.x.x" + +"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.1": + version "8.5.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" + integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== + +"@hapi/sntp@3.x.x": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@hapi/sntp/-/sntp-3.1.2.tgz#e7d8d64e50625a43f2cb712f8fa6aa40fa955c78" + integrity sha512-i2UehKbFPKtKVXhp4v7wV3qJxkGV2TAPlZ5YSpmsqv/2eygXYYI+etBJ5r4T8kbyslhxgqQyHNS6xstL92Vmrg== + dependencies: + "@hapi/boom" "7.x.x" + "@hapi/bounce" "1.x.x" + "@hapi/hoek" "8.x.x" + "@hapi/teamwork" "3.x.x" + +"@hapi/teamwork@3.x.x": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@hapi/teamwork/-/teamwork-3.3.1.tgz#b52d0ec48682dc793926bd432e22ceb19c915d3f" + integrity sha512-61tiqWCYvMKP7fCTXy0M4VE6uNIwA0qvgFoiDubgfj7uqJ0fdHJFQNnVPGrxhLWlwz0uBPWrQlBH7r8y9vFITQ== + +bower@^1.8.8: + version "1.8.12" + resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.12.tgz#44cfca2a5e04b8d9a066621e24c8b179d8ac321e" + integrity sha512-u1xy9SrwwoPlgjuHNjhV+YUPVdqyBj2ALBxuzeIUKXaPI2i2xypGgxqXkuHcITGdi5yBj5JuXgyMvgiWiS1S3Q== + +fastclick@ftlabs/fastclick#1.0.6: + version "1.0.6" + resolved "https://codeload.github.com/ftlabs/fastclick/tar.gz/9977a916739360ad4ffd7aa19b0016bf375e934b" + +foundation@zurb/bower-foundation#5.5.2: + version "5.5.2" + resolved "https://codeload.github.com/zurb/bower-foundation/tar.gz/9bad0646cb1c41d230e79ffe381491b7f703fc52" + +fuzzysearch@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fuzzysearch/-/fuzzysearch-1.0.3.tgz#dffc80f6d6b04223f2226aa79dd194231096d008" + integrity sha1-3/yA9tawQiPyImqnndGUIxCW0Ag= + +gist-async@razor-x/gist-async#2.0.2: + version "2.0.2" + resolved "https://codeload.github.com/razor-x/gist-async/tar.gz/8e5314e106a23cf4925d7265a37517d1f017c008" + +hawk@^7.0.10: + version "7.1.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-7.1.2.tgz#559c9be58be7d3c6869a62ef66c813bf17b82376" + integrity sha512-Pa8cMp2f/pFUF9B7cJuBHrF8PYPQmVXe2CfxyrgUmmfRNHMHuQOBpIFHk/eCFrHLVqLlAf2kU7BRxks7814TmA== + dependencies: + "@hapi/b64" "4.x.x" + "@hapi/boom" "7.x.x" + "@hapi/cryptiles" "4.x.x" + "@hapi/hoek" "8.x.x" + "@hapi/sntp" "3.x.x" + +headjs@headjs/headjs#1.0.3: + version "1.0.3" + resolved "https://codeload.github.com/headjs/headjs/tar.gz/edc8427191a633d80e7372c49e6d28a098be766f" + +highlightjs@components/highlightjs#8.8.0: + version "0.0.0" + resolved "https://codeload.github.com/components/highlightjs/tar.gz/950ac24569cbadfd82fd4fe2a7b60e5fbd14fef6" + +hoek@^6.1.3: + version "6.1.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-6.1.3.tgz#73b7d33952e01fe27a38b0457294b79dd8da242c" + integrity sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ== + +jquery-placeholder@mathiasbynens/jquery-placeholder#~2.0.7: + version "0.0.0" + resolved "https://codeload.github.com/mathiasbynens/jquery-placeholder/tar.gz/510a577397713934b46ccaceaa7ecc558cff313a" + +jquery.cookie@carhartl/jquery-cookie#~1.4.0: + version "1.4.1" + resolved "https://codeload.github.com/carhartl/jquery-cookie/tar.gz/7f88a4e631aba8a8c688fd8999ce6b9bcfd50718" + +jquery@jquery/jquery-dist#^3.0.0: + version "3.6.0" + resolved "https://codeload.github.com/jquery/jquery-dist/tar.gz/e786e3d9707ffd9b0dd330ca135b66344dcef85a" + +modernizr@Modernizr/Modernizr#2.8.3: + version "0.0.0" + resolved "https://codeload.github.com/Modernizr/Modernizr/tar.gz/d6bb30c0f12ebb3ddd01e90b0bf435e1c34e6f11" + +normalize-css@necolas/normalize.css#3.0.3: + version "3.0.3" + resolved "https://codeload.github.com/necolas/normalize.css/tar.gz/2bdda84272650aedfb45d8abe11a6d177933a803" + +picturefill@scottjehl/picturefill#2.3.1: + version "2.3.1" + resolved "https://codeload.github.com/scottjehl/picturefill/tar.gz/4e6db73fea78124092be5ba424d053a008a92a6b" + +simple-jekyll-search@christian-fei/Simple-Jekyll-Search#^1.7.2: + version "1.9.1" + resolved "https://codeload.github.com/christian-fei/Simple-Jekyll-Search/tar.gz/67a9d73a56a9e2c186b7083ccabf9afcde1ba146" + dependencies: + fuzzysearch "^1.0.3" + +webfontloader@typekit/webfontloader#1.6.6: + version "1.6.6" + resolved "https://codeload.github.com/typekit/webfontloader/tar.gz/f804211f044b4fe07a2654f2ee1d14e4bce63316"